Explorar el Código

* 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://svn.code.sf.net/p/rathena/svn/trunk@11036 54d463be-8e91-2dee-dedb-b68131a5f0ec

ultramage hace 18 años
padre
commit
97e812dda1
Se han modificado 6 ficheros con 362 adiciones y 423 borrados
  1. 5 0
      Changelog-Trunk.txt
  2. 61 60
      conf-tmpl/charcommand_athena.conf
  3. 1 1
      src/map/map.h
  4. 4 3
      src/map/npc.c
  5. 2 0
      src/map/npc.h
  6. 289 359
      src/map/npc_chat.c

+ 5 - 0
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)

+ 61 - 60
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
 
 //---------------------------

+ 1 - 1
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 {

+ 4 - 3
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) {

+ 2 - 0
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

+ 289 - 359
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