diff options
author | ultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2007-08-19 06:04:34 +0000 |
---|---|---|
committer | ultramage <ultramage@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2007-08-19 06:04:34 +0000 |
commit | 8f4119ce9a0b70de6380c1d032a4cb6e5b51787d (patch) | |
tree | b68f4fd457de57168ede9a1457853f7ad4e76f70 | |
parent | 72d890661194b248620c5c353777cb96be18c821 (diff) | |
download | hercules-8f4119ce9a0b70de6380c1d032a4cb6e5b51787d.tar.gz hercules-8f4119ce9a0b70de6380c1d032a4cb6e5b51787d.tar.bz2 hercules-8f4119ce9a0b70de6380c1d032a4cb6e5b51787d.tar.xz hercules-8f4119ce9a0b70de6380c1d032a4cb6e5b51787d.zip |
* Fixed a deallocation mistake and some buffer overflows in npc_chat.c after doing rtfm@pcre.txt (all caused by incorrect usage of pcre api)
* Removed underscores in npc_chat.c's variable names (easier to read)
* Reindented the whole thing (used spaces half of the time ._.)
* Moved npc pcre-data deallocation from npc_remove_map to npc_unload
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@11036 54d463be-8e91-2dee-dedb-b68131a5f0ec
-rw-r--r-- | Changelog-Trunk.txt | 5 | ||||
-rw-r--r-- | conf-tmpl/charcommand_athena.conf | 121 | ||||
-rw-r--r-- | src/map/map.h | 2 | ||||
-rw-r--r-- | src/map/npc.c | 7 | ||||
-rw-r--r-- | src/map/npc.h | 2 | ||||
-rw-r--r-- | src/map/npc_chat.c | 648 |
6 files changed, 362 insertions, 423 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index d72a48ea9..0928916ad 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -3,6 +3,11 @@ Date Added AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. +2007/08/18 + * Fixed a deallocation mistake and some buffer overflows in npc_chat.c + after doing rtfm@pcre.txt (all caused by incorrect usage of pcre api) + * Removed underscores in npc_chat.c's variable names (easier to read) + * Moved npc pcre-data deallocation from npc_remove_map to npc_unload 2007/08/17 * Implemented the official dual-wield aspd equation [ultramage] - using 0.7 instead of 0.66 as modifier (so aspd will be lower now) diff --git a/conf-tmpl/charcommand_athena.conf b/conf-tmpl/charcommand_athena.conf index 927a44054..acd89779a 100644 --- a/conf-tmpl/charcommand_athena.conf +++ b/conf-tmpl/charcommand_athena.conf @@ -1,13 +1,13 @@ // Athena charcommand Configuration file. // Translated by Peter Kieser <pfak@telus.net> -// Set here the symbol that you want to use for your commands -// Only 1 character is get (default is '#'). You can set any character, -// except control-character (0x00-0x1f), '%' (party chat speaking), -// '/' (standard ragnarok GM commands) and '@' (Standard GM Commands) -// With default character, all commands begin by a '#', example: #save SomePlayer +// The symbol that will be used to recognize commands. +// You can set any one character, except control-characters (0x00-0x1f), +// '%', '$' (party/guild chat speaking) and '/' (standard client commands). +// The symbol must be different from from the standard GM command symbol. command_symbol: # + //-------------------------- // 0: normal player commands // None for security purposes. @@ -25,85 +25,86 @@ command_symbol: # // 40: Sub-GM commands -//View the items in a character's cart +// View the items in a character's cart cartlist: 40 -//Apply an effect onto another character +// Apply an effect onto another character effect: 40 -//View the exp of a character +// View the exp of a character exp: 40 -//List a chacter's items +// List a chacter's items itemlist: 40 -//View the jail time remaining +// View the jail time remaining jailtime: 40 -//Refresh a character +// Refresh a character refresh: 40 -//List a chacter's stats +// List a chacter's stats stats: 40 -//List a chacter's storage items +// List a chacter's storage items storagelist: 40 //--------------------- // 50: Sub-GM+ commands -//Change a character's clothing color +// Change a character's clothing color dye: 50 -//Give another character a fake name +// Give another character a fake name fakename: 50 -//Open the hatch dialog for a character +// Open the hatch dialog for a character hatch: 50 -//Change a character's hair color +// Change a character's hair color hcolor: 50 haircolor: 50 -//Change a character's hair style +// Change a character's hair style hstyle: 50 hairstyle: 50 // Changes character's model model: 50 -//Give or remove a peco from a character +// Give or remove a peco from a character mount: 50 mountpeco: 50 -//Make another character's pet friendly/not +// Make another character's pet friendly/not petfriendly: 50 -//Rename another character's pet +// Rename another character's pet petrename: 50 -//Change a character's size +// Change a character's size size: 50 //---------------- // 60: GM commands -//Resurrects a dead character +// Resurrects a dead character alive: 60 +revive: 60 -//Give a player all the skills available to him/her +// Give a player all the skills available to him/her allskill: 60 allskills: 60 skillall: 60 skillsall: 60 -//Give a character the maximum possible stats +// Give a character the maximum possible stats allstat: 60 allstats: 60 statall: 60 statsall: 60 -//Change another character's base level (3 same commands) +// Change another character's base level (3 same commands) blvl: 60 blevel: 60 baselvl: 60 @@ -112,118 +113,118 @@ baselevel: 60 // Changes the sex of an online player (all characters on the account) changesex: 60 -//Delete items from a character +// Delete items from a character delitem: 60 -//Disguise a character +// Disguise a character disguise: 60 undisguise: 60 -//Resets another character's designated maps +// Resets another character's designated maps feelreset: 60 -//Change the guild level for a character's guild +// Change the guild level for a character's guild glvl: 60 glevel: 60 guildlvl: 60 guildlevel: 60 -//Open guild storage for a character +// Open guild storage for a character gstorage: 60 -//Heal a character +// Heal a character heal: 60 -//Invoke GM Hide on a character +// Invoke GM Hide on a character hide: 60 -//Increase a character's homunculus' level +// Increase a character's homunculus' level hlvl: 60 hlevel: 60 homlvl: 60 homlevel: 60 -//Evolve a character's homunculus +// Evolve a character's homunculus homevolve: 60 homevolution: 60 -//Change a character's homunculus' friendly value +// Change a character's homunculus' friendly value homfriendly: 60 -//Change a character's homunculus' hunger value +// Change a character's homunculus' hunger value homhungry: 60 -//View a character's homunculus' stats +// View a character's homunculus' stats hominfo: 40 -//Give another character an item +// Give another character an item item: 60 -//Create a specific item (with cards, refines, etc +// Create a specific item (with cards, refines, etc item2: 60 -//Remove all of a character's possessions +// Remove all of a character's possessions itemreset: 60 -//Change another character's job (2 same commands) +// Change another character's job (2 same commands) job: 60 jobchange: 60 -//Change another character's job level (3 same commands) +// Change another character's job level (3 same commands) jlvl: 60 jlevel: 60 joblvl: 60 joblevel: 60 -//Allow a character to attack anybody +// Allow a character to attack anybody killer: 60 -//Make a character killable by anybody +// Make a character killable by anybody killable: 60 -//Return a character to their respawn point +// Return a character to their respawn point load: 60 -//Take away a character's platinum skill +// Take away a character's platinum skill lostskill: 60 -//Make a character immune to monsters +// Make a character immune to monsters monsterignore: 60 -//Apply a certain option to another character +// Apply a certain option to another character option: 60 -//Change a character's pet's hungry value +// Change a character's pet's hungry value pethungry: 60 -//Produce forged equipment on a character (as if he/she was a blacksmith) +// Produce forged equipment on a character (as if he/she was a blacksmith) produce: 60 -//Give another character a platinum skill +// Give another character a platinum skill questskill: 60 -//Performs a stat and skill reset on someone else. +// Performs a stat and skill reset on someone else. reset: 60 -//Save another character +// Save another character save: 60 // Gives another character skill points skpoint: 60 -//Change a character's walking speed +// Change a character's walking speed speed: 60 -//Give another character spiritball effect +// Give another character spiritball effect spiritball: 60 -//Open storage for a character +// Open storage for a character storage: 60 // Gives another character status points stpoint: 60 -//Change a character's stats +// Change a character's stats str: 60 agi: 60 vit: 60 @@ -243,10 +244,10 @@ rura+: 60 //---------------------- // 80: GM Chief commands -//Refine a character's equipment +// Refine a character's equipment refine: 80 -//Give another character zeny +// Give another character zeny zeny: 80 //--------------------------- diff --git a/src/map/map.h b/src/map/map.h index 01af03789..4ec216a3e 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -844,7 +844,7 @@ struct npc_data { int eventtimer[MAX_EVENTTIMER]; short arenaflag; - void *chatdb; + void* chatdb; // pointer to a npc_parse struct (see npc_chat.c) struct npc_data *master_nd; union { diff --git a/src/map/npc.c b/src/map/npc.c index b5fc1cacf..352161189 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -1441,9 +1441,6 @@ int npc_remove_map(struct npc_data* nd) if(nd->bl.prev == NULL || nd->bl.m < 0) return 1; //Not assigned to a map. m = nd->bl.m; -#ifdef PCRE_SUPPORT - npc_chat_finalize(nd); -#endif clif_clearunit_area(&nd->bl,2); //Remove corresponding NPC CELLs if (nd->bl.subtype == WARP) { @@ -1513,6 +1510,10 @@ int npc_unload(struct npc_data* nd) if (nd->chat_id) // remove npc chatroom object and kick users chat_deletenpcchat(nd); +#ifdef PCRE_SUPPORT + npc_chat_finalize(nd); // deallocate npc PCRE data structures +#endif + if (nd->bl.subtype == SCRIPT) { ev_db->foreach(ev_db,npc_unload_ev,nd->exname); //Clean up all events related. if (nd->u.scr.timerid != -1) { diff --git a/src/map/npc.h b/src/map/npc.h index 74d49dd3c..2ce21d473 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -4,6 +4,8 @@ #ifndef _NPC_H_ #define _NPC_H_ +#include "map.h" // TBL_NPC + #define START_NPC_NUM 110000000 #define WARP_CLASS 45 diff --git a/src/map/npc_chat.c b/src/map/npc_chat.c index 7d3a9a2fa..a1fdae0bc 100644 --- a/src/map/npc_chat.c +++ b/src/map/npc_chat.c @@ -3,27 +3,22 @@ #ifdef PCRE_SUPPORT -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <time.h> - #include "../common/timer.h" #include "../common/malloc.h" -#include "../common/version.h" #include "../common/nullpo.h" #include "../common/showmsg.h" +#include "../common/strlib.h" -#include "map.h" -#include "status.h" -#include "npc.h" -#include "chat.h" -#include "script.h" -#include "battle.h" +#include "map.h" // struct mob_data, struct npc_data +#include "script.h" // set_var() #include "pcre.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + /** * Written by MouseJstr in a vision... (2/21/2005) * @@ -71,24 +66,21 @@ * deletes a pset */ -/* Structure containing all info associated with a single pattern - block */ - +/* Structure containing all info associated with a single pattern block */ struct pcrematch_entry { - struct pcrematch_entry *next_; - char *pattern_; - pcre *pcre_; - pcre_extra *pcre_extra_; - char *label_; + struct pcrematch_entry* next; + char* pattern; + pcre* pcre; + pcre_extra* pcre_extra; + char* label; }; -/* A set of patterns that can be activated and deactived with a single - command */ - +/* A set of patterns that can be activated and deactived with a single command */ struct pcrematch_set { - struct pcrematch_set *next_, *prev_; - struct pcrematch_entry *head_; - int setid_; + struct pcrematch_set* prev; + struct pcrematch_set* next; + struct pcrematch_entry* head; + int setid; }; /* @@ -100,10 +92,9 @@ struct pcrematch_set { * also wanted people to be able to grab this one file to get updates * without having to do a large number of changes. */ - struct npc_parse { - struct pcrematch_set *active_; - struct pcrematch_set *inactive_; + struct pcrematch_set* active; + struct pcrematch_set* inactive; }; @@ -112,63 +103,51 @@ struct npc_parse { * * This does NOT do the list management */ - -void finalize_pcrematch_entry(struct pcrematch_entry *e) +void finalize_pcrematch_entry(struct pcrematch_entry* e) { -//TODO: For some odd reason this causes a already-free'd error under Windows, but not *nix! [Skotlex] -#ifndef _WIN32 - if (e->pcre_) { - free(e->pcre_); - e->pcre_ = NULL; - } -#endif - if (e->pcre_extra_) { - free(e->pcre_extra_); - e->pcre_ = NULL; - } - aFree(e->pattern_); - aFree(e->label_); + pcre_free(e->pcre); + pcre_free(e->pcre_extra); + aFree(e->pattern); + aFree(e->label); } /** * Lookup (and possibly create) a new set of patterns by the set id */ -static struct pcrematch_set * lookup_pcreset(struct npc_data *nd,int setid) +static struct pcrematch_set* lookup_pcreset(struct npc_data* nd, int setid) { - struct pcrematch_set *pcreset; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) - nd->chatdb = npcParse = (struct npc_parse *) - aCalloc(sizeof(struct npc_parse), 1); - - pcreset = npcParse->active_; - - while (pcreset != NULL) { - if (pcreset->setid_ == setid) - break; - pcreset = pcreset->next_; - } - if (pcreset == NULL) - pcreset = npcParse->inactive_; - - while (pcreset != NULL) { - if (pcreset->setid_ == setid) - break; - pcreset = pcreset->next_; - } - - if (pcreset == NULL) { - pcreset = (struct pcrematch_set *) - aCalloc(sizeof(struct pcrematch_set), 1); - pcreset->next_ = npcParse->inactive_; - if (pcreset->next_ != NULL) - pcreset->next_->prev_ = pcreset; - pcreset->prev_ = 0; - npcParse->inactive_ = pcreset; - pcreset->setid_ = setid; - } - - return pcreset; + struct pcrematch_set *pcreset; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + nd->chatdb = npcParse = (struct npc_parse *) aCalloc(sizeof(struct npc_parse), 1); + + pcreset = npcParse->active; + + while (pcreset != NULL) { + if (pcreset->setid == setid) + break; + pcreset = pcreset->next; + } + if (pcreset == NULL) + pcreset = npcParse->inactive; + + while (pcreset != NULL) { + if (pcreset->setid == setid) + break; + pcreset = pcreset->next; + } + + if (pcreset == NULL) { + pcreset = (struct pcrematch_set *) aCalloc(sizeof(struct pcrematch_set), 1); + pcreset->next = npcParse->inactive; + if (pcreset->next != NULL) + pcreset->next->prev = pcreset; + pcreset->prev = 0; + npcParse->inactive = pcreset; + pcreset->setid = setid; + } + + return pcreset; } /** @@ -176,33 +155,32 @@ static struct pcrematch_set * lookup_pcreset(struct npc_data *nd,int setid) * * if the setid does not exist, this will silently return */ - -static void activate_pcreset(struct npc_data *nd,int setid) +static void activate_pcreset(struct npc_data* nd, int setid) { - struct pcrematch_set *pcreset; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) - return; // Nothing to activate... - pcreset = npcParse->inactive_; - while (pcreset != NULL) { - if (pcreset->setid_ == setid) - break; - pcreset = pcreset->next_; - } - if (pcreset == NULL) - return; // not in inactive list - if (pcreset->next_ != NULL) - pcreset->next_->prev_ = pcreset->prev_; - if (pcreset->prev_ != NULL) - pcreset->prev_->next_ = pcreset->next_; - else - npcParse->inactive_ = pcreset->next_; - - pcreset->prev_ = NULL; - pcreset->next_ = npcParse->active_; - if (pcreset->next_ != NULL) - pcreset->next_->prev_ = pcreset; - npcParse->active_ = pcreset; + struct pcrematch_set *pcreset; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + return; // Nothing to activate... + pcreset = npcParse->inactive; + while (pcreset != NULL) { + if (pcreset->setid == setid) + break; + pcreset = pcreset->next; + } + if (pcreset == NULL) + return; // not in inactive list + if (pcreset->next != NULL) + pcreset->next->prev = pcreset->prev; + if (pcreset->prev != NULL) + pcreset->prev->next = pcreset->next; + else + npcParse->inactive = pcreset->next; + + pcreset->prev = NULL; + pcreset->next = npcParse->active; + if (pcreset->next != NULL) + pcreset->next->prev = pcreset; + npcParse->active = pcreset; } /** @@ -210,138 +188,133 @@ static void activate_pcreset(struct npc_data *nd,int setid) * * if the setid does not exist, this will silently return */ - -static void deactivate_pcreset(struct npc_data *nd,int setid) +static void deactivate_pcreset(struct npc_data* nd, int setid) { - struct pcrematch_set *pcreset; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) - return; // Nothing to deactivate... - if (setid == -1) { - while(npcParse->active_ != NULL) - deactivate_pcreset(nd, npcParse->active_->setid_); - return; - } - pcreset = npcParse->active_; - while (pcreset != NULL) { - if (pcreset->setid_ == setid) - break; - pcreset = pcreset->next_; - } - if (pcreset == NULL) - return; // not in active list - if (pcreset->next_ != NULL) - pcreset->next_->prev_ = pcreset->prev_; - if (pcreset->prev_ != NULL) - pcreset->prev_->next_ = pcreset->next_; - else - npcParse->active_ = pcreset->next_; - - pcreset->prev_ = NULL; - pcreset->next_ = npcParse->inactive_; - if (pcreset->next_ != NULL) - pcreset->next_->prev_ = pcreset; - npcParse->inactive_ = pcreset; + struct pcrematch_set *pcreset; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + return; // Nothing to deactivate... + if (setid == -1) { + while(npcParse->active != NULL) + deactivate_pcreset(nd, npcParse->active->setid); + return; + } + pcreset = npcParse->active; + while (pcreset != NULL) { + if (pcreset->setid == setid) + break; + pcreset = pcreset->next; + } + if (pcreset == NULL) + return; // not in active list + if (pcreset->next != NULL) + pcreset->next->prev = pcreset->prev; + if (pcreset->prev != NULL) + pcreset->prev->next = pcreset->next; + else + npcParse->active = pcreset->next; + + pcreset->prev = NULL; + pcreset->next = npcParse->inactive; + if (pcreset->next != NULL) + pcreset->next->prev = pcreset; + npcParse->inactive = pcreset; } /** * delete a set of patterns. */ -static void delete_pcreset(struct npc_data *nd,int setid) +static void delete_pcreset(struct npc_data* nd, int setid) { - int active = 1; - struct pcrematch_set *pcreset; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) - return; // Nothing to deactivate... - pcreset = npcParse->active_; - while (pcreset != NULL) { - if (pcreset->setid_ == setid) - break; - pcreset = pcreset->next_; - } - if (pcreset == NULL) { - active = 0; - pcreset = npcParse->inactive_; - while (pcreset != NULL) { - if (pcreset->setid_ == setid) - break; - pcreset = pcreset->next_; - } - } - if (pcreset == NULL) - return; - - if (pcreset->next_ != NULL) - pcreset->next_->prev_ = pcreset->prev_; - if (pcreset->prev_ != NULL) - pcreset->prev_->next_ = pcreset->next_; - + int active = 1; + struct pcrematch_set *pcreset; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + return; // Nothing to deactivate... + pcreset = npcParse->active; + while (pcreset != NULL) { + if (pcreset->setid == setid) + break; + pcreset = pcreset->next; + } + if (pcreset == NULL) { + active = 0; + pcreset = npcParse->inactive; + while (pcreset != NULL) { + if (pcreset->setid == setid) + break; + pcreset = pcreset->next; + } + } + if (pcreset == NULL) + return; + + if (pcreset->next != NULL) + pcreset->next->prev = pcreset->prev; + if (pcreset->prev != NULL) + pcreset->prev->next = pcreset->next; + if(active) - npcParse->active_ = pcreset->next_; + npcParse->active = pcreset->next; else - npcParse->inactive_ = pcreset->next_; - - pcreset->prev_ = NULL; - pcreset->next_ = NULL; - - while (pcreset->head_) { - struct pcrematch_entry *n = pcreset->head_->next_; - finalize_pcrematch_entry(pcreset->head_); - aFree(pcreset->head_); // Cleanin' the last ones.. [Lance] - pcreset->head_ = n; - } - + npcParse->inactive = pcreset->next; + + pcreset->prev = NULL; + pcreset->next = NULL; + + while (pcreset->head) { + struct pcrematch_entry* n = pcreset->head->next; + finalize_pcrematch_entry(pcreset->head); + aFree(pcreset->head); // Cleanin' the last ones.. [Lance] + pcreset->head = n; + } + aFree(pcreset); } /** * create a new pattern entry */ -static struct pcrematch_entry *create_pcrematch_entry(struct pcrematch_set * set) +static struct pcrematch_entry* create_pcrematch_entry(struct pcrematch_set* set) { - struct pcrematch_entry * e = (struct pcrematch_entry *) - aCalloc(sizeof(struct pcrematch_entry), 1); - struct pcrematch_entry * last = set->head_; - - // Normally we would have just stuck it at the end of the list but - // this doesn't sink up with peoples usage pattern. They wanted - // the items defined first to have a higher priority then the - // items defined later.. as a result, we have to do some work up - // front.. - - /* if we are the first pattern, stick us at the end */ - if (last == NULL) { - set->head_ = e; - return e; - } - - /* Look for the last entry */ - while (last->next_ != NULL) - last = last->next_; - - last->next_ = e; - e->next_ = NULL; - - return e; + struct pcrematch_entry * e = (struct pcrematch_entry *) aCalloc(sizeof(struct pcrematch_entry), 1); + struct pcrematch_entry * last = set->head; + + // Normally we would have just stuck it at the end of the list but + // this doesn't sink up with peoples usage pattern. They wanted + // the items defined first to have a higher priority then the + // items defined later. as a result, we have to do some work up front. + + /* if we are the first pattern, stick us at the end */ + if (last == NULL) { + set->head = e; + return e; + } + + /* Look for the last entry */ + while (last->next != NULL) + last = last->next; + + last->next = e; + e->next = NULL; + + return e; } /** * define/compile a new pattern */ - -void npc_chat_def_pattern(struct npc_data *nd, int setid, - const char *pattern, const char *label) +void npc_chat_def_pattern(struct npc_data* nd, int setid, const char* pattern, const char* label) { - const char *err; - int erroff; - - struct pcrematch_set * s = lookup_pcreset(nd, setid); - struct pcrematch_entry *e = create_pcrematch_entry(s); - e->pattern_ = aStrdup(pattern); - e->label_ = aStrdup(label); - e->pcre_ = pcre_compile(pattern, PCRE_CASELESS, &err, &erroff, NULL); - e->pcre_extra_ = pcre_study(e->pcre_, 0, &err); + const char *err; + int erroff; + + struct pcrematch_set * s = lookup_pcreset(nd, setid); + struct pcrematch_entry *e = create_pcrematch_entry(s); + e->pattern = aStrdup(pattern); + e->label = aStrdup(label); + e->pcre = pcre_compile(pattern, PCRE_CASELESS, &err, &erroff, NULL); + e->pcre_extra = pcre_study(e->pcre, 0, &err); } /** @@ -350,18 +323,18 @@ void npc_chat_def_pattern(struct npc_data *nd, int setid, * * this could be more efficent but.. how often do you do this? */ -void npc_chat_finalize(struct npc_data *nd) +void npc_chat_finalize(struct npc_data* nd) { - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - if (npcParse == NULL) - return; - - while(npcParse->active_) - delete_pcreset(nd, npcParse->active_->setid_); - - while(npcParse->inactive_) - delete_pcreset(nd, npcParse->inactive_->setid_); - + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + return; + + while(npcParse->active) + delete_pcreset(nd, npcParse->active->setid); + + while(npcParse->inactive) + delete_pcreset(nd, npcParse->inactive->setid); + // Additional cleaning up [Lance] aFree(npcParse); } @@ -369,158 +342,115 @@ void npc_chat_finalize(struct npc_data *nd) /** * Handler called whenever a global message is spoken in a NPC's area */ -int npc_chat_sub(struct block_list *bl, va_list ap) +int npc_chat_sub(struct block_list* bl, va_list ap) { - struct npc_data *nd = (struct npc_data *)bl; - struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; - char *msg; - int len, pos, i; - struct map_session_data *sd; - struct npc_label_list *lst; - struct pcrematch_set *pcreset; - - // Not interested in anything you might have to say... - if (npcParse == NULL || npcParse->active_ == NULL) - return 0; - - msg = va_arg(ap,char*); - len = va_arg(ap,int); - sd = va_arg(ap,struct map_session_data *); - - // grab the active list - pcreset = npcParse->active_; - - // interate across all active sets - while (pcreset != NULL) { - struct pcrematch_entry *e = pcreset->head_; - // interate across all patterns in that set - while (e != NULL) { - int offsets[20]; - char buf[255]; - // perform pattern match - int r = pcre_exec(e->pcre_, e->pcre_extra_, msg, len, 0, - 0, offsets, sizeof(offsets) / sizeof(offsets[0])); - if (r >= 0) { - // save out the matched strings - switch (r) { - case 10: - memcpy(buf, &msg[offsets[18]], offsets[19]); - buf[offsets[19]] = '\0'; - set_var(sd, "$@p9$", buf); - case 9: - memcpy(buf, &msg[offsets[16]], offsets[17]); - buf[offsets[17]] = '\0'; - set_var(sd, "$@p8$", buf); - case 8: - memcpy(buf, &msg[offsets[14]], offsets[15]); - buf[offsets[15]] = '\0'; - set_var(sd, "$@p7$", buf); - case 7: - memcpy(buf, &msg[offsets[12]], offsets[13]); - buf[offsets[13]] = '\0'; - set_var(sd, "$@p6$", buf); - case 6: - memcpy(buf, &msg[offsets[10]], offsets[11]); - buf[offsets[11]] = '\0'; - set_var(sd, "$@p5$", buf); - case 5: - memcpy(buf, &msg[offsets[8]], offsets[9]); - buf[offsets[9]] = '\0'; - set_var(sd, "$@p4$", buf); - case 4: - memcpy(buf, &msg[offsets[6]], offsets[7]); - buf[offsets[7]] = '\0'; - set_var(sd, "$@p3$", buf); - case 3: - memcpy(buf, &msg[offsets[4]], offsets[5]); - buf[offsets[5]] = '\0'; - set_var(sd, "$@p2$", buf); - case 2: - memcpy(buf, &msg[offsets[2]], offsets[3]); - buf[offsets[3]] = '\0'; - set_var(sd, "$@p1$", buf); - case 1: - memcpy(buf, &msg[offsets[0]], offsets[1]); - buf[offsets[1]] = '\0'; - set_var(sd, "$@p0$", buf); - } - - // find the target label.. this sucks.. - lst=nd->u.scr.label_list; - pos = -1; - for (i = 0; i < nd->u.scr.label_list_num; i++) { - if (strncmp(lst[i].name, e->label_, sizeof(lst[i].name)) == 0) { - pos = lst[i].pos; - break; - } - } - if (pos == -1) { - ShowWarning("Unable to find label: %s", e->label_); - // unable to find label... do something.. - return 0; - } - // run the npc script - run_script(nd->u.scr.script,pos,sd->bl.id,nd->bl.id); - return 0; - } - e = e->next_; - } - pcreset = pcreset->next_; - } - - return 0; + struct npc_data* nd = (struct npc_data *) bl; + struct npc_parse* npcParse = (struct npc_parse *) nd->chatdb; + char* msg; + int len, i; + struct map_session_data* sd; + struct npc_label_list* lst; + struct pcrematch_set* pcreset; + struct pcrematch_entry* e; + + // Not interested in anything you might have to say... + if (npcParse == NULL || npcParse->active == NULL) + return 0; + + msg = va_arg(ap,char*); + len = va_arg(ap,int); + sd = va_arg(ap,struct map_session_data *); + + // iterate across all active sets + for (pcreset = npcParse->active; pcreset != NULL; pcreset = pcreset->next) + { + // interate across all patterns in that set + for (e = pcreset->head; e != NULL; e = e->next) + { + int offsets[2*10 + 10]; // 1/3 reserved for temp space requred by pcre_exec + + // perform pattern match + int r = pcre_exec(e->pcre, e->pcre_extra, msg, len, 0, 0, offsets, ARRAYLENGTH(offsets)); + if (r > 0) + { + // save out the matched strings + for (i = 0; i < r; i++) + { + char var[6], val[255]; + snprintf(var, sizeof(var), "$@p%i$", i); + pcre_copy_substring(msg, offsets, r, i, val, sizeof(val)); + set_var(sd, var, val); + } + + // find the target label.. this sucks.. + lst = nd->u.scr.label_list; + ARR_FIND(0, nd->u.scr.label_list_num, i, strncmp(lst[i].name, e->label, sizeof(lst[i].name)) == 0); + if (i == nd->u.scr.label_list_num) { + ShowWarning("Unable to find label: %s", e->label); + return 0; + } + + // run the npc script + run_script(nd->u.scr.script,lst[i].pos,sd->bl.id,nd->bl.id); + return 0; + } + } + } + + return 0; } -int mob_chat_sub(struct block_list *bl, va_list ap){ +int mob_chat_sub(struct block_list* bl, va_list ap) +{ struct mob_data *md = (struct mob_data *)bl; - if(md->nd){ + if(md->nd) npc_chat_sub(&md->nd->bl, ap); - } + return 0; } // Various script builtins used to support these functions -int buildin_defpattern(struct script_state *st) +int buildin_defpattern(struct script_state* st) { - int setid=conv_num(st,& (st->stack->stack_data[st->start+2])); - const char *pattern=conv_str(st,& (st->stack->stack_data[st->start+3])); - const char *label=conv_str(st,& (st->stack->stack_data[st->start+4])); - struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid); - - npc_chat_def_pattern(nd, setid, pattern, label); - - return 0; + int setid = conv_num(st,& (st->stack->stack_data[st->start+2])); + const char* pattern = conv_str(st,& (st->stack->stack_data[st->start+3])); + const char* label = conv_str(st,& (st->stack->stack_data[st->start+4])); + struct npc_data* nd = (struct npc_data *)map_id2bl(st->oid); + + npc_chat_def_pattern(nd, setid, pattern, label); + + return 0; } -int buildin_activatepset(struct script_state *st) +int buildin_activatepset(struct script_state* st) { - int setid=conv_num(st,& (st->stack->stack_data[st->start+2])); - struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid); - - activate_pcreset(nd, setid); - - return 0; + int setid = conv_num(st,& (st->stack->stack_data[st->start+2])); + struct npc_data* nd = (struct npc_data *)map_id2bl(st->oid); + + activate_pcreset(nd, setid); + + return 0; } -int buildin_deactivatepset(struct script_state *st) +int buildin_deactivatepset(struct script_state* st) { - int setid=conv_num(st,& (st->stack->stack_data[st->start+2])); - struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid); - - deactivate_pcreset(nd, setid); - - return 0; + int setid = conv_num(st,& (st->stack->stack_data[st->start+2])); + struct npc_data* nd = (struct npc_data *)map_id2bl(st->oid); + + deactivate_pcreset(nd, setid); + + return 0; } -int buildin_deletepset(struct script_state *st) +int buildin_deletepset(struct script_state* st) { - int setid=conv_num(st,& (st->stack->stack_data[st->start+2])); - struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid); - - delete_pcreset(nd, setid); - - return 0; + int setid = conv_num(st,& (st->stack->stack_data[st->start+2])); + struct npc_data* nd = (struct npc_data *)map_id2bl(st->oid); + + delete_pcreset(nd, setid); + + return 0; } #endif //PCRE_SUPPORT |