From ab878900afdb9c9caa58b7f84f0a12b6283edf2b Mon Sep 17 00:00:00 2001 From: Haru Date: Tue, 11 Mar 2014 04:19:59 +0100 Subject: Added --load-plugin commandline argument Signed-off-by: Haru --- src/char/char.c | 2 +- src/common/HPM.c | 9 +++++++-- src/common/HPM.h | 2 +- src/login/login.c | 2 +- src/map/map.c | 23 +++++++++++++++++++++-- 5 files changed, 31 insertions(+), 7 deletions(-) (limited to 'src') 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/map.c b/src/map/map.c index a7e83cae3..b2d50292e 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -5356,6 +5356,7 @@ void map_helpscreen(bool do_exit) ShowInfo(" --inter-config Alternative inter-server configuration.\n"); ShowInfo(" --log-config Alternative logging configuration.\n"); ShowInfo(" --script-check Tests a script for errors, without running the server.\n"); + ShowInfo(" --load-plugin Loads an additional plugin (can be repeated).\n"); HPM->arg_help();/* display help for commands implemented thru HPM */ if( do_exit ) exit(EXIT_SUCCESS); @@ -5566,7 +5567,8 @@ int do_init(int argc, char *argv[]) { bool minimal = false; char *scriptcheck = NULL; - int i; + int i, extra_plugins_count = 0; + const char **extra_plugins = NULL; #ifdef GCOLLECT GC_enable_incremental(); @@ -5579,7 +5581,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(extra_plugins, const char *, ++extra_plugins_count); + extra_plugins[extra_plugins_count-1] = argv[++i]; + } + } + } + HPM->config_read(extra_plugins, extra_plugins_count); + if (extra_plugins) { + aFree(extra_plugins); + extra_plugins = NULL; + extra_plugins_count = 0; + } HPM->event(HPET_PRE_INIT); @@ -5629,6 +5645,9 @@ int do_init(int argc, char *argv[]) runflag = CORE_ST_STOP; if( map->arg_next_value(arg, i, argc, true) ) scriptcheck = argv[++i]; + } else if( strcmp(arg, "load-plugin") == 0 ) { + if( map->arg_next_value(arg, i, argc, true) ) + i++; } else { ShowError("Unknown option '%s'.\n", argv[i]); exit(EXIT_FAILURE); -- cgit v1.2.3-70-g09d2 From 0e58529609ae84540ca340193abf9ca1e8166b72 Mon Sep 17 00:00:00 2001 From: Haru Date: Tue, 11 Mar 2014 05:06:38 +0100 Subject: Added --load-script commandline argument Signed-off-by: Haru --- script-checker | 19 ++++++++++++----- script-checker.bat | 2 +- src/map/atcommand.c | 2 +- src/map/map.c | 59 ++++++++++++++++++++++++++++++++++++----------------- src/map/map.h | 2 +- 5 files changed, 57 insertions(+), 27 deletions(-) (limited to 'src') 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 " 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/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 b2d50292e..9dbe19666 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,9 @@ void map_helpscreen(bool do_exit) ShowInfo(" --grf-path Alternative GRF path configuration.\n"); ShowInfo(" --inter-config Alternative inter-server configuration.\n"); ShowInfo(" --log-config Alternative logging configuration.\n"); - ShowInfo(" --script-check 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 Loads an additional script (can be repeated).\n"); ShowInfo(" --load-plugin Loads an additional plugin (can be repeated).\n"); HPM->arg_help();/* display help for commands implemented thru HPM */ if( do_exit ) @@ -5566,9 +5573,9 @@ void map_load_defaults(void) { int do_init(int argc, char *argv[]) { bool minimal = false; - char *scriptcheck = NULL; - int i, extra_plugins_count = 0; - const char **extra_plugins = NULL; + bool scriptcheck = false; + int i, load_extras_count = 0; + const char **load_extras = NULL; #ifdef GCOLLECT GC_enable_incremental(); @@ -5585,16 +5592,16 @@ int do_init(int argc, char *argv[]) const char* arg = argv[i]; if( strcmp(arg, "--load-plugin") == 0 ) { if( map->arg_next_value(arg, i, argc, true) ) { - RECREATE(extra_plugins, const char *, ++extra_plugins_count); - extra_plugins[extra_plugins_count-1] = argv[++i]; + RECREATE(load_extras, const char *, ++load_extras_count); + load_extras[load_extras_count-1] = argv[++i]; } } } - HPM->config_read(extra_plugins, extra_plugins_count); - if (extra_plugins) { - aFree(extra_plugins); - extra_plugins = NULL; - extra_plugins_count = 0; + HPM->config_read(load_extras, load_extras_count); + if (load_extras) { + aFree(load_extras); + load_extras = NULL; + load_extras_count = 0; } HPM->event(HPET_PRE_INIT); @@ -5643,11 +5650,15 @@ int do_init(int argc, char *argv[]) } else if( strcmp(arg, "script-check") == 0 ) { map->minimal = true; runflag = CORE_ST_STOP; - if( map->arg_next_value(arg, i, argc, true) ) - scriptcheck = argv[++i]; + scriptcheck = true; } else if( strcmp(arg, "load-plugin") == 0 ) { if( map->arg_next_value(arg, i, argc, true) ) i++; + } else if( strcmp(arg, "load-script") == 0 ) { + if( map->arg_next_value(arg, i, argc, true) ) { + RECREATE(load_extras, const char *, ++load_extras_count); + load_extras[load_extras_count-1] = argv[++i]; + } } else { ShowError("Unknown option '%s'.\n", argv[i]); exit(EXIT_FAILURE); @@ -5675,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, load_extras, load_extras_count); chrif->checkdefaultlogin(); @@ -5785,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); -- cgit v1.2.3-70-g09d2 From d117462c3921a4f7a5eaa3c1760d774e81ff8fba Mon Sep 17 00:00:00 2001 From: "Hercules.ws" Date: Sun, 16 Mar 2014 23:23:21 +0100 Subject: HPM Hooks Update Signed-off-by: HerculesWSAPI --- src/plugins/HPMHooking/HPMHooking.Hooks.inc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/plugins/HPMHooking/HPMHooking.Hooks.inc b/src/plugins/HPMHooking/HPMHooking.Hooks.inc index 78987f81a..b2fbb9518 100644 --- a/src/plugins/HPMHooking/HPMHooking.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking.Hooks.inc @@ -35401,13 +35401,14 @@ struct mob_data* HP_map_id2boss(int id) { } return retVal___; } -void HP_map_reloadnpc(bool clear) { +void HP_map_reloadnpc(bool clear, , int extra_scripts_count) { +/* Error: Unhandled var type 'char *const *extra_scripts' */ int hIndex = 0; if( HPMHooks.count.HP_map_reloadnpc_pre ) { - void (*preHookFunc) (bool *clear); + void (*preHookFunc) (bool *clear, , 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_count); } if( *HPMforce_return ) { *HPMforce_return = false; @@ -35415,13 +35416,13 @@ void HP_map_reloadnpc(bool clear) { } } { - HPMHooks.source.map.reloadnpc(clear); + HPMHooks.source.map.reloadnpc(clear, , extra_scripts_count); } if( HPMHooks.count.HP_map_reloadnpc_post ) { - void (*postHookFunc) (bool *clear); + void (*postHookFunc) (bool *clear, , 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_count); } } return; -- cgit v1.2.3-70-g09d2 From 649dc74e6ae7813dbd0a7ad1844278ee629e038c Mon Sep 17 00:00:00 2001 From: "Hercules.ws" Date: Mon, 17 Mar 2014 02:17:06 +0100 Subject: HPM Hooks Update Signed-off-by: HerculesWSAPI --- src/plugins/HPMHooking/HPMHooking.Hooks.inc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/plugins/HPMHooking/HPMHooking.Hooks.inc b/src/plugins/HPMHooking/HPMHooking.Hooks.inc index b2fbb9518..396b241b0 100644 --- a/src/plugins/HPMHooking/HPMHooking.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking.Hooks.inc @@ -35401,14 +35401,13 @@ struct mob_data* HP_map_id2boss(int id) { } return retVal___; } -void HP_map_reloadnpc(bool clear, , int extra_scripts_count) { -/* Error: Unhandled var type 'char *const *extra_scripts' */ +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, , int *extra_scripts_count); + 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, , &extra_scripts_count); + preHookFunc(&clear, extra_scripts, &extra_scripts_count); } if( *HPMforce_return ) { *HPMforce_return = false; @@ -35416,13 +35415,13 @@ void HP_map_reloadnpc(bool clear, , int extra_scripts_count) { } } { - HPMHooks.source.map.reloadnpc(clear, , extra_scripts_count); + HPMHooks.source.map.reloadnpc(clear, extra_scripts, extra_scripts_count); } if( HPMHooks.count.HP_map_reloadnpc_post ) { - void (*postHookFunc) (bool *clear, , int *extra_scripts_count); + 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, , &extra_scripts_count); + postHookFunc(&clear, extra_scripts, &extra_scripts_count); } } return; -- cgit v1.2.3-70-g09d2 From 1cf8ea92f8e8e992617addc371272c78e60df219 Mon Sep 17 00:00:00 2001 From: Haru Date: Mon, 17 Mar 2014 17:13:11 +0100 Subject: Follow-up to 0e58529 (for MSVC compatibility) - Fixes bugreport:8097, thanks to Frost http://hercules.ws/board/tracker/issue-8097-compile-issue-using-msvc-2010-windows-7-64bit/ Signed-off-by: Haru --- src/map/map.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/map/map.c b/src/map/map.c index 9dbe19666..dfcc7f47a 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -5575,7 +5575,7 @@ int do_init(int argc, char *argv[]) bool minimal = false; bool scriptcheck = false; int i, load_extras_count = 0; - const char **load_extras = NULL; + char **load_extras = NULL; #ifdef GCOLLECT GC_enable_incremental(); @@ -5592,12 +5592,12 @@ int do_init(int argc, char *argv[]) const char* arg = argv[i]; if( strcmp(arg, "--load-plugin") == 0 ) { if( map->arg_next_value(arg, i, argc, true) ) { - RECREATE(load_extras, const char *, ++load_extras_count); + RECREATE(load_extras, char *, ++load_extras_count); load_extras[load_extras_count-1] = argv[++i]; } } } - HPM->config_read(load_extras, load_extras_count); + HPM->config_read((const char * const *)load_extras, load_extras_count); if (load_extras) { aFree(load_extras); load_extras = NULL; @@ -5656,7 +5656,7 @@ int do_init(int argc, char *argv[]) i++; } else if( strcmp(arg, "load-script") == 0 ) { if( map->arg_next_value(arg, i, argc, true) ) { - RECREATE(load_extras, const char *, ++load_extras_count); + RECREATE(load_extras, char *, ++load_extras_count); load_extras[load_extras_count-1] = argv[++i]; } } else { @@ -5686,7 +5686,7 @@ int do_init(int argc, char *argv[]) map->config_read_sub(map->MAP_CONF_NAME); // loads npcs - map->reloadnpc(false, load_extras, load_extras_count); + map->reloadnpc(false, (const char * const *)load_extras, load_extras_count); chrif->checkdefaultlogin(); -- cgit v1.2.3-70-g09d2 From 42da97d7979f5db56d50072dfd7787ebf549ab1b Mon Sep 17 00:00:00 2001 From: Haru Date: Fri, 20 Sep 2013 04:28:50 +0200 Subject: 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 --- doc/script_commands.txt | 66 ++++++++++++++++++++++++++------- npc/custom/test.txt | 17 ++++++++- src/map/script.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++-- src/map/script.h | 4 ++ 4 files changed, 166 insertions(+), 18 deletions(-) (limited to 'src') 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("",""); + +This command is only available if the server is compiled with regular +expressions library enabled. + +The string will be searched for a match to the regular expression +, 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 That matched the full pattern. +- $@regexmatch$[1 .. $@regexmatchcount]: The parts of that matched + each of the parenthesized capture-groups in . + +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 ,"",""; *activatepset ; *deactivatepset ; *deletepset ; 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/custom/test.txt index 00f9c376e..6d1c6b49f 100644 --- a/npc/custom/test.txt +++ b/npc/custom/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/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 { -- cgit v1.2.3-70-g09d2