Page 2 of 3

Posted: Wed Dec 01, 2004 6:18 pm
by bushdaka
I found that by taking the chew function that was posted and pasting it into the latest blech.h (thus replacing the existing chew) that all my events fire correctly. This includes some that had problems before the latest mod was introduced. If I take the October zip blech.h and compile that into the 1125 release then events work the same as they did in October <g>. With just the 1125 blech.h I miss all kinds of events with some pattern I couldn't figure out in my macro. Next I need to look at the 1125 blech.h chew function and compare it to the posted chew function and see what has to be done to make it support multiple event firing.

Posted: Wed Dec 01, 2004 7:35 pm
by Starbucks
I know that with RH, any sort of event where the letter "r" is in the name, will not trigger. I can do /secondassist abcdefghijklmnopqstuvwxyz and it'll work...I throw an "r" on the end and it won't take it.

more info

Posted: Tue Dec 07, 2004 1:14 am
by Sequoyah
I am using afnuke macro. Using the 11/25 MQ2 and the 12/2 macro, typing /afhelp will send it south. All kinds of events triggered that shouldn't be. The "Command" variable has various text snippets that make no sense.

I have tried using the 11/25 build with the blech.h from 10/25 - same thing. Used a pur 10/25 build - same thing again. Any ideas? Any help you can provide would be appreciated.

Thanks,

Sequoyah

Posted: Wed Dec 08, 2004 1:47 am
by Cr4zyb4rd
This is the blech.h we were all using for quite a while before Lax started tinkering with it again. You should be able to just use this along with everything else in the recent zip, and not have any problems.

It has a few issues, but they're ones that were known about for quite a while, and most of the current/popular macros should work well with it.

Code: Select all

/*****************************************************************************
    Blech.h
	Lax/Blech  
    Copyright (C) 2004 Lax

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License, version 2, as published by
    the Free Software Foundation.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
******************************************************************************/

/*****************************************************************************
About Blech:
	Blech is a text parser API.  It uses callback system to allow it to retrieve
	current values of variables from your program, and to initiate an event from
	a successful match.  Events are added, text is fed through it, and hopefully
	you get what you want....

    Blech uses a B-Tree implementation where each node can have n nodes.  The
	data stored by each node is a portion of a string.  Nodes are split when a
	sibling is being added that begins with the same data as an existing one.
	Example:
	existing child of a node: "blech"-(possibly existing children)
    insert child to node:     "bleach"
    
	resulting nodes:          "ch"-(possibly existing children)
	                    "ble"<
                              "ach"
	The end result using this implementation is a way to compare a given string to
	many strings with possibly variable portions, where a hash/map/binary tree will
	fail.

Using Blech:
	*Initialize the Blech class:
	Blech MyBlech('#'); // Use only a variable "scan"
	Blech MyBlech('#','|',VariableValue); // Use a variable "scan" and a variable "print"

	*Add events:
	MyBlech.AddEvent("Text with #variable# portion",MyEvent,0);
	
	*Create event callback:
	void __stdcall MyEvent(unsigned long ID, void * pData, PBLECHVALUE pValues)
	{
		printf("MyEvent(%d,%X,%X)",ID,pData,pValues);
		while(pValues)
		{
			printf("'%s'=>'%s'",pValues->Name,pValues->Value);
			pValues=pValues->pNext;
		}
	}

	*Feed Blech:
	MyBlech.Feed("Text with some portion");

	*Examine output:
	MyEvent(1,0,(pointer))
	'variable'=>'some'

******************************************************************************/

#pragma once

#define BLECHVERSION "Lax/Blech 1.5.2"

#include <map>
#include <string>

//#ifdef WIN32
#ifdef BLECH_DEBUG
//#pragma message(BLECHVERSION)
//#pragma message("Blech: Debug Mode")
#include <windows.h>
#define BLECHASSERT(x) if (!(x)) {BlechDebug("Blech Assertion failure: %s",#x); __asm{int 3};}
static void BlechDebug(char *szFormat, ...)
{
    char szOutput[4096] = {0};
    va_list vaList;

    va_start( vaList, szFormat );
    vsprintf(szOutput,szFormat, vaList);
    OutputDebugString(szOutput);
    OutputDebugString("\n");
}
#define BlechTry(x) BlechDebug("Trying %s",#x);x;BlechDebug("%s complete",#x)
#else
#define BLECHASSERT(x) 
#define BlechTry(x) x
#define BlechDebug //
#endif

#ifdef BLECH_CASE_SENSITIVE
//#pragma message("Blech: Case Sensitive")
#define STRCMP(A,B) strcmp(A,B)
#define STRNCMP(A,B,LENGTH) strncmp(A,B,LENGTH)
#define STRFIND(HAYSTACK,NEEDLE) strstr(HAYSTACK,NEEDLE)
#else
//#pragma message("Blech: Case Insensitive")
#define STRCMP(A,B) stricmp(A,B)
#define STRNCMP(A,B,LENGTH) strnicmp(A,B,LENGTH)
#define STRFIND(HAYSTACK,NEEDLE) stristr(HAYSTACK,NEEDLE)
#endif
//#else
//#error Non-Win32 defines not yet available
//#endif


enum eBlechStringType
{
	BST_NORMAL=0,
	BST_PRINTVAR=1,
	BST_SCANVAR=2,
};


typedef struct _BLECHVALUE {
	char * Name;
	char * Value;
	struct _BLECHVALUE *pNext;
} BLECHVALUE, *PBLECHVALUE;

typedef unsigned long   (__stdcall *fBlechVariableValue)(char * VarName, char * Value);
typedef void (__stdcall *fBlechCallback)(unsigned long ID, void * pData, PBLECHVALUE pValues);

typedef struct _BLECHEVENT {
	unsigned long ID;
	void * pData;
	char * OriginalString;
	fBlechCallback Callback;

	class BlechNode *pBlechNode;
} BLECHEVENT, *PBLECHEVENT;

typedef std::map<unsigned long,PBLECHEVENT> BLECHEVENTMAP; 

typedef struct _BLECHEVENTNODE {
	PBLECHEVENT pEvent;

	struct _BLECHEVENTNODE *pNext;
	struct _BLECHEVENTNODE *pPrev;
} BLECHEVENTNODE, *PBLECHEVENTNODE;

static unsigned long Equalness(char *StringA, char *StringB)
{
	BlechDebug("Equalness(%s,%s)",StringA,StringB);
	char *pPos=StringA;
	while(1)
	{
		if (*pPos!=*StringB)
		{
#ifndef BLECH_CASE_SENSITIVE
			if (*pPos>='a' && *pPos<='z')
			{
				if ((*pPos)-32==*StringB)
				{
					++pPos;
					++StringB;
					continue;
				}
			}
			else if (*pPos>='A' && *pPos<='Z')
			{
				if ((*pPos)+32==*StringB)
				{
					++pPos;
					++StringB;
					continue;
				}
			}
#endif
			unsigned long Ret=(unsigned long)(pPos-StringA);
				BlechDebug("Equalness returning %d",Ret);
			return Ret;
		}
		else
		{
			if (!*pPos)
			{
				unsigned long Ret=(unsigned long)(pPos-StringA);
				BlechDebug("Equalness returning %d",Ret);
				return Ret;
			}
		}
		++pPos;
		++StringB;
	}
}

class BlechNode
{
public:
	BlechNode(BlechNode *Parent, BlechNode **Root, char * String, eBlechStringType NewStringType=BST_NORMAL)
	{
		BlechDebug("BlechNode(%X,%X,%s,%d)",Parent,Root,String,NewStringType);
		BLECHASSERT(String && *String);
		BLECHASSERT(Root);
		StringType=NewStringType;
		if (StringType==BST_NORMAL)
			Length=(unsigned long)strlen(String);
		else
			Length=0;
		pString=strdup(String);
		pParent=Parent;
		ppRoot=Root;
		pChildren=0;
		pNext=0;
		pPrev=0;
		pEvents=0;
	}

	~BlechNode()
	{
		BlechDebug("~BlechNode()");
		// clean out chillins
		while(pChildren)
		{
			BlechNode *pNext=pChildren->pNext;
			delete pChildren;
			pChildren=pNext;
		}
		// clean out events
		while(pEvents)
		{
			pEvents->pEvent->pBlechNode=0;
			PBLECHEVENTNODE pNext=pEvents->pNext;
			delete pEvents;
			pEvents=pNext;
		}
		// remove me from my siblings
		if (pPrev)
			pPrev->pNext=pNext;
		else
		{
			// set parent's first child / root
			if (pParent)
				pParent->pChildren=pNext;
			else
				*ppRoot=pNext;
		}
		if (pNext)
			pNext->pPrev=pPrev;

		// free string
		free(pString);
	}

	BlechNode *AddChild(char *NewString, eBlechStringType NewStringType)
	{
		BlechDebug("AddChild(%s,%d)",NewString,NewStringType);
		BLECHASSERT(NewString);
		
		BlechNode *pChild = pChildren;
		while(pChild)
		{
			if (pChild->StringType==NewStringType)
			{
				if (NewStringType==BST_NORMAL)
				{
					if (unsigned long Eq=Equalness(pChild->pString,NewString))
					{
						unsigned long Len=(unsigned long)strlen(NewString);
						if (Len==Eq)
						{
							if (Eq==pChild->Length)
							{
								return pChild;
							}
							// old child needs to be child of new child!
							
							// make new child, redo pChild as child of new child...
							BlechNode *pNode = new BlechNode(this,ppRoot,NewString,NewStringType);
							BLECHASSERT(pNode);
							if (pNode->pNext=pChild->pNext)
								pNode->pNext->pPrev=pNode;
							if (pNode->pPrev=pChild->pPrev)
								pNode->pPrev->pNext=pNode;
							else
								pChildren=pNode;
							pChild->pNext=0;
							pChild->pPrev=0;

							pChild->pParent=pNode;
							pNode->pChildren=pChild;
							memmove(pChild->pString,&pChild->pString[Eq],pChild->Length-Eq+1);
							pChild->Length-=Eq;

							return pNode;
							// and return that new child
						}
						else if (Eq==pChild->Length)
						{
							// easy one
							return pChild->AddChild(&NewString[Eq],NewStringType);
						}
						// both children (new and old) need to be children of a new child

						// make new child, redo pChild as child of new child...
						char Temp=pChild->pString[Eq];
						pChild->pString[Eq]=0;
						BlechNode *pNode = new BlechNode(this,ppRoot,pChild->pString,NewStringType);
						pChild->pString[Eq]=Temp;
						BLECHASSERT(pNode);
						if (pNode->pNext=pChild->pNext)
							pNode->pNext->pPrev=pNode;
						if (pNode->pPrev=pChild->pPrev)
							pNode->pPrev->pNext=pNode;
						else
							pChildren=pNode;
						pChild->pNext=0;
						pChild->pPrev=0;


						pChild->pParent=pNode;
						pNode->pChildren=pChild;

						memmove(pChild->pString,&pChild->pString[Eq],pChild->Length-Eq+1);
						pChild->Length-=Eq;
						return pNode->AddChild(&NewString[Eq],NewStringType);
						// and return a very new child!
					}
				}
				else
				{
					if (!strcmp(pChild->pString,NewString))
						return pChild;
				}
			}
			pChild=pChild->pNext;
		}


		BlechNode *pNode = new BlechNode(this,ppRoot,NewString,NewStringType);
		BLECHASSERT(pNode);
		pNode->pNext=pChildren;
		if (pChildren)
			pChildren->pPrev=pNode;
		pChildren=pNode;
		return pChildren;
	}

	inline bool IsEmpty()
	{
		return (!pChildren && !pEvents);
	}

	inline void AddEvent(PBLECHEVENT pEvent)
	{
		BlechDebug("AddEvent(%X)",pEvent);
		BLECHASSERT(pEvent);
		
		PBLECHEVENTNODE pNode=new BLECHEVENTNODE;
		pNode->pEvent=pEvent;
		pNode->pNext=pEvents;
		if (pEvents)
			pEvents->pPrev=pNode;
		pNode->pPrev=0;
		pEvent->pBlechNode=this;
		pEvents=pNode;
	}

	void RemoveEvent(PBLECHEVENT pEvent)
	{
		BlechDebug("RemoveEvent(%X)",pEvent);
		BLECHASSERT(pEvent);
		PBLECHEVENTNODE pNode=pEvents;
		while(pNode)
		{
			if (pEvent==pNode->pEvent)
			{
				if (pNode->pNext)
					pNode->pNext->pPrev=pNode->pPrev;
				if (pNode->pPrev)
					pNode->pPrev->pNext=pNode->pNext;
				else
					pEvents=pNode->pNext;
				delete pNode;
				return;
			}
			pNode=pNode->pNext;
		}
	}

	eBlechStringType StringType;
	char * pString;
	unsigned long Length;
	BlechNode *pParent;
	BlechNode **ppRoot;
	BlechNode *pChildren;
	BlechNode *pNext;
	BlechNode *pPrev;

	PBLECHEVENTNODE pEvents;
};

class Blech
{
public:
	Blech(char ScanDelimiter,char PrintDelimiter,fBlechVariableValue PrintRetriever)
	{
		BlechDebug("Blech(%c,%c,%X)",ScanDelimiter,PrintDelimiter,PrintRetriever);
		BLECHASSERT(PrintDelimiter);
		BLECHASSERT(PrintRetriever);
		PrintVarDelimiter=PrintDelimiter;
		ScanVarDelimiter=ScanDelimiter;
		VariableValue=PrintRetriever;
		Initialize();
	}
	Blech(char ScanDelimiter=0)
	{
		BlechDebug("Blech(%c)",ScanDelimiter);
		ScanVarDelimiter=ScanDelimiter;
		PrintVarDelimiter=0;
		VariableValue=0;
		Initialize();
	}

	void Reset()
	{
		Cleanup();
		Event.clear();
//		ExactMatch.clear();
		Initialize();
	}

	~Blech(void)
	{
		BlechDebug("~Blech()");
		Cleanup();
	}

	unsigned long Feed(char * Input)
	{
		BlechDebug("Feed(%s)",Input);
		if (!Input || !Input[0])
			return 0;
		unsigned long Root=(unsigned char)Input[0];
#ifndef BLECH_CASE_SENSITIVE
				if (Root>='a' && Root<='z')
					Root-=32;
#endif
		return Chew(Tree[Root],Input)+Chew(Tree[0],Input)/*+Swallow(Input)/**/;
	}

	inline bool IsExact(char *Text)
	{
		if (!strchr(Text,ScanVarDelimiter) && (!PrintVarDelimiter || !strchr(Text,PrintVarDelimiter)))
			return true;
		return false;
	}

	/*
	unsigned long AddExactEvent(char *Text,fBlechCallback Callback,void *pData=0)
	{
		PBLECHEVENT pEvent = new BLECHEVENT;
		pEvent->Callback=Callback;
		pEvent->pData=pData;
		pEvent->ID=++LastID;
		pEvent->pBlechNode=0;
		pEvent->OriginalString=strdup(Text);

		BlechDebug("AddEvent(%X)",pEvent);
		BLECHASSERT(pEvent);
		
		PBLECHEVENTNODE pNode=new BLECHEVENTNODE;
		pNode->pEvent=pEvent;
#ifndef BLECH_CASE_SENSITIVE
		char Temp[4096];
		PBLECHEVENTNODE pEvents=ExactMatch[strlwr(strcpy(Temp,pEvent->OriginalString))];
#else
		PBLECHEVENTNODE pEvents=ExactMatch[Text];
#endif
		pNode->pNext=pEvents;
		if (pEvents)
			pEvents->pPrev=pNode;
		pNode->pPrev=0;
#ifndef BLECH_CASE_SENSITIVE
		ExactMatch[Temp]=pNode;
#else
		ExactMatch[Text]=pNode;
#endif

		Event[pEvent->ID]=pEvent;
		return pEvent->ID;

	}
	/**/

	unsigned long AddEvent(char *Text,fBlechCallback Callback,void *pData=0)
	{
		BlechDebug("AddEvent(%s,%X,%X)",Text,Callback,pData);
		BLECHASSERT(Text);
		BLECHASSERT(Callback);
//		if (IsExact(Text))
//		{
//			return AddExactEvent(Text,Callback,pData);
//		}
		char *pText=Text;
		char *Part=Text;
		eBlechStringType StringType=BST_NORMAL;
		BlechNode *pNode=0;
		while(*pText)
		{
			if (*pText==ScanVarDelimiter)
			{
				if (Part!=pText)
					pNode=AddNode(pNode,Part,pText,StringType);
				Part=&pText[1];
				if (StringType==BST_SCANVAR)
					StringType=BST_NORMAL;
				else
					StringType=BST_SCANVAR;
			}
			else
			if (*pText==PrintVarDelimiter)
			{
				if (Part!=pText)
					pNode=AddNode(pNode,Part,pText,StringType);
				Part=&pText[1];
				if (StringType==BST_PRINTVAR)
					StringType=BST_NORMAL;
				else
					StringType=BST_PRINTVAR;
			}
			pText++;
		}
		if (*Part)
		{
			pNode=AddNode(pNode,Part,pText,StringType);
		}
		// add event to node
		BLECHASSERT(pNode);
		PBLECHEVENT pEvent = new BLECHEVENT;
		pEvent->Callback=Callback;
		pEvent->pData=pData;
		pEvent->ID=++LastID;
		pEvent->pBlechNode=pNode;
		pEvent->OriginalString=strdup(Text);
		pNode->AddEvent(pEvent);
		Event[pEvent->ID]=pEvent;
		return pEvent->ID;
	}

	bool RemoveEvent(unsigned long ID)
	{
		BlechDebug("RemoveEvent(%d)",ID);
		PBLECHEVENT pEvent = Event[ID];
		if (!pEvent)
			return false;
		Event.erase(ID);
//		if (pEvent->pBlechNode)
		{
			free(pEvent->OriginalString);

			BlechNode *pNode=pEvent->pBlechNode;
			while(pNode && pNode->IsEmpty())
			{
				BlechNode *pNext=pNode->pParent;
				delete pNode;
				pNode=pNext;
			}
		}
		/*
		else
		{
			// exact match
#ifndef BLECH_CASE_SENSITIVE
			char Temp[4096];
			PBLECHEVENTNODE pNode=ExactMatch[strlwr(strcpy(Temp,pEvent->OriginalString))];
#else
			PBLECHEVENTNODE pNode=ExactMatch[pEvent->OriginalString];
#endif
			if (pNode->pNext)
				pNode->pNext->pPrev=pNode->pPrev;
			if (pNode->pPrev)
				pNode->pPrev->pNext=pNode->pNext;
			else
#ifndef BLECH_CASE_SENSITIVE
				ExactMatch[Temp]=pNode->pNext;
#else
				ExactMatch[pEvent->OriginalString]=pNode->pNext;
#endif
			delete pNode;
			free(pEvent->OriginalString);
			delete pEvent;
		}
		/**/
		return true;
	}

	char Version[32];

private:
	inline void Cleanup()
	{
		for (unsigned long N = 0 ; N < 256 ; N++)
		{
			delete Tree[N];
		}
		for (BLECHEVENTMAP::iterator i=Event.begin(); i != Event.end(); i++)
		{
			PBLECHEVENT pEvent=i->second;
			BLECHASSERT(pEvent);
			BlechTry(free(pEvent->OriginalString));
			delete pEvent;
		}
	}


	char *stristr(char *haystack,char *needle)
	{
		BlechDebug("stristr(%s,%s)",haystack,needle);
		unsigned long HaystackLength=(unsigned long)strlen(haystack);
		unsigned long NeedleLength=(unsigned long)strlen(needle);
		if (NeedleLength>HaystackLength)
			return 0;//nope
		if (NeedleLength==HaystackLength)
		{
			if (!STRCMP(haystack,needle))
				return haystack;
			return 0;
		}
		HaystackLength++;
		NeedleLength++;
		char *pHaystack=(char*)malloc(HaystackLength);
		char *pNeedle=(char*)malloc(NeedleLength);
		memcpy(pHaystack,haystack,HaystackLength);
		memcpy(pNeedle,needle,NeedleLength);
        strlwr(pHaystack);
		strlwr(pNeedle);
		char *pReturn=strstr(pHaystack,pNeedle);
		if (pReturn)
		{
			pReturn=haystack+(pReturn-pHaystack);
		}
		free(pHaystack);
		free(pNeedle);
		return pReturn;
	}
/*
	unsigned long Swallow(char * Input)
	{
		BlechDebug("Swallow(%s)",Input);
#ifndef BLECH_CASE_SENSITIVE
		char Temp[4096];
		PBLECHEVENTNODE pEventNode=ExactMatch[strlwr(strcpy(Temp,Input))];
		if (!pEventNode)
			ExactMatch.erase(Temp);
#else
		PBLECHEVENTNODE pEventNode=ExactMatch[Input];
		if (!pEventNode)
			ExactMatch.erase(Input);
#endif
		unsigned long Count=0;
			while(pEventNode)
			{
			Count++;
			pEventNode->pEvent->Callback(pEventNode->pEvent->ID,pEventNode->pEvent->pData,0);
				pEventNode=pEventNode->pNext;
			}
		return Count;
	}
/**/

unsigned long Chew(BlechNode *pNode,char * Input) 
{ 
   BlechDebug("Blech: Chew(%X, %s)",pNode,Input); 
   BLECHASSERT(Input); 
   if (!pNode) 
      return 0; 
   unsigned int InputLength=(unsigned int)strlen(Input); 

   PBLECHEVENTNODE pEventNode=0; 
   BlechNode **InputNodeMatch; 
   InputNodeMatch = new BlechNode* [InputLength]; 
   unsigned int Pos = 0; 

   char VarData[4096]; 

   for (unsigned int i=0; i<InputLength; InputNodeMatch[i++]=0); 

   bool MoveUpChain = false; 

   while (pNode) 
   { 
      switch(pNode->StringType) 
      { 
      case BST_NORMAL: 
         { 
            unsigned int NodeStringLength=(unsigned int)strlen(pNode->pString); 
            if (strnicmp(Input+Pos, pNode->pString, NodeStringLength)==0) {      // strings match 
               for (unsigned int i=0; i<NodeStringLength; InputNodeMatch[Pos+i++]=pNode); 
               Pos+=NodeStringLength; 
               if (!pNode->pChildren) {                                             // if no children 
                  if (Pos==InputLength) {                                             // must be at end of string to be a match 
                     pEventNode=pNode->pEvents; 
                     pNode=0; 
                  } else { 
                     for (; Pos>0 && InputNodeMatch[Pos-1]==pNode; InputNodeMatch[Pos-1]=0,Pos--); 
                     MoveUpChain = true; 
                  } 
               } else { 
                  pNode=pNode->pChildren; 
               } 
            } else { 
               for (; Pos>0 && InputNodeMatch[Pos-1]==pNode; InputNodeMatch[Pos-1]=0,Pos--); 
               MoveUpChain = true; 
            } 
         } 
         break; 
      case BST_PRINTVAR: 
         { 
            if (Pos>0 && InputNodeMatch[Pos-1]==pNode) { 
               for (; Pos>0 && InputNodeMatch[Pos-1]==pNode; InputNodeMatch[Pos-1]=0,Pos--); 
               MoveUpChain = true; 
               break; 
            } 

            unsigned int VarLength = VariableValue(pNode->pString,VarData); 
            if (VarLength) { 
               if (strnicmp(Input+Pos, VarData, VarLength)==0) {      // strings match 
                  for (unsigned int i=0; i<VarLength; InputNodeMatch[Pos+i++]=pNode); 
                  Pos+=VarLength; 
                  if (!pNode->pChildren) {                                                // if no children 
                     if (Pos==InputLength) {                                          // must be at end of string to be a match 
                        pEventNode=pNode->pEvents; 
                        pNode=0; 
                     } else { 
                        for (; Pos>0 && InputNodeMatch[Pos-1]==pNode; InputNodeMatch[Pos-1]=0,Pos--); 
                        MoveUpChain = true; 
                     } 
                  } else { 
                     pNode=pNode->pChildren; 
                  } 

               } else { 
                  MoveUpChain = true; 
               } 
            } else { 
               MoveUpChain = true; 
            } 
         } 
         break; 
      case BST_SCANVAR: 
         if (!pNode->pChildren) {            // if no children, match to end of string and return 
            for (;Pos<InputLength; InputNodeMatch[Pos++]=pNode); 
            pEventNode=pNode->pEvents; 
            pNode=0; 
         } 
         else                                          // children, increment wildcard match by 1 and move to children 
         { 
            if (Pos<InputLength) {            // space to increment match by 1 
               InputNodeMatch[Pos++]=pNode; 
               pNode=pNode->pChildren; 
            } 
            else                                       // no space for wildcard, move to next sibling or back up to parent 
            { 
               for (; Pos>0 && InputNodeMatch[Pos-1]==pNode; InputNodeMatch[Pos-1]=0,Pos--); 
               MoveUpChain = true; 
            } 
         } 
         break; 
      } 
      if (MoveUpChain) 
      { 
         if (pNode->pNext) 
            pNode=pNode->pNext; 
         else 
            pNode=pNode->pParent; 
         MoveUpChain = false; 
      } 
   } 
    
   PBLECHVALUE pValues=0; 
   pNode=0; 
   for (unsigned int i=0; i<InputLength; i++) { 
      if (pNode!=InputNodeMatch[i]) { 
         pNode=InputNodeMatch[i]; 
         if (pNode->StringType==BST_SCANVAR) { 
            PBLECHVALUE pValue = new BLECHVALUE; 
            pValue->Name=pNode->pString; 
             
            unsigned int j; 
            for (j=i+1; j<InputLength && InputNodeMatch[j]==pNode; j++); 
            pValue->Value=new char [1+j-i]; 
            strncpy(pValue->Value, Input+i, j-i); 
            pValue->Value[j-i]=0; 
            pValue->pNext=pValues; 
            pValues=pValue; 
         } 
      } 
   } 

   unsigned int eventCount=0; 
   while (pEventNode) 
   { 
      eventCount++; 
      pEventNode->pEvent->Callback(pEventNode->pEvent->ID, pEventNode->pEvent->pData, pValues); 
      pEventNode=pEventNode->pNext; 
   } 

   while(pValues) 
   { 
      PBLECHVALUE pNext=pValues->pNext; 
      delete [] pValues->Value; 
      delete pValues; 
      pValues=pNext; 
   } 

   delete [] InputNodeMatch; 
   return eventCount; 
} 
	BlechNode *AddNode(unsigned long nRoot, char *String, eBlechStringType StringType)
	{
		BlechDebug("AddNode(%d,%s,%d)",nRoot,String,StringType);
		BLECHASSERT(nRoot<256);
		BLECHASSERT(String);


		BlechNode *pChild = Tree[nRoot];
		while(pChild)
		{
			if (pChild->StringType==StringType)
			{
				if (StringType==BST_NORMAL)
				{
					if (unsigned long Eq=Equalness(pChild->pString,String))
					{
						unsigned long Len=(unsigned long)strlen(String);
						if (Len==Eq)
						{
							if (Eq==pChild->Length)
							{
								return pChild;
							}
							// old child needs to be child of new child!
							
							// make new child, redo pChild as child of new child...
							BlechNode *pNode = new BlechNode(0,&Tree[nRoot],String,StringType);
							BLECHASSERT(pNode);
							if (pNode->pNext=pChild->pNext)
								pNode->pNext->pPrev=pNode;
							if (pNode->pPrev=pChild->pPrev)
								pNode->pPrev->pNext=pNode;
							else
								Tree[nRoot]=pNode;
							pChild->pNext=0;
							pChild->pPrev=0;

							pChild->pParent=pNode;
							pNode->pChildren=pChild;
							memmove(pChild->pString,&pChild->pString[Eq],pChild->Length-Eq+1);
							pChild->Length-=Eq;

							return pNode;
							// and return that new child
						}
						else if (Eq==pChild->Length)
						{
							// easy one
							return pChild->AddChild(&String[Eq],StringType);
						}
						// both children (new and old) need to be children of a new child

						// make new child, redo pChild as child of new child...
						char Temp=pChild->pString[Eq];
						pChild->pString[Eq]=0;
						BlechNode *pNode = new BlechNode(0,&Tree[nRoot],pChild->pString,StringType);
						pChild->pString[Eq]=Temp;
						BLECHASSERT(pNode);
						if (pNode->pNext=pChild->pNext)
							pNode->pNext->pPrev=pNode;
						if (pNode->pPrev=pChild->pPrev)
							pNode->pPrev->pNext=pNode;
						else
							Tree[nRoot]=pNode;
						pChild->pNext=0;
						pChild->pPrev=0;


						pChild->pParent=pNode;
						pNode->pChildren=pChild;

						memmove(pChild->pString,&pChild->pString[Eq],pChild->Length-Eq+1);
						pChild->Length-=Eq;
						return pNode->AddChild(&String[Eq],StringType);
						// and return a very new child!
					}
				}
				else
				{
					if (!strcmp(pChild->pString,String))
						return pChild;
				}
			}
			pChild=pChild->pNext;
		}



		BlechNode *pNode = new BlechNode(0,&Tree[nRoot],String,StringType);
		BLECHASSERT(pNode);

		pNode->pNext=Tree[nRoot];
		if (Tree[nRoot])
			Tree[nRoot]->pPrev=pNode;
		Tree[nRoot]=pNode;

		return pNode;
	}

	BlechNode *AddNode(BlechNode *pNode, char *StringBegin, char *StringEnd, eBlechStringType StringType)
	{
		BlechDebug("AddNode(%X,%s,%X,%d)",pNode,StringBegin,StringEnd,StringType);
		BLECHASSERT(StringBegin && *StringBegin);
		BLECHASSERT(StringEnd);

		unsigned long Len=(unsigned long)(StringEnd-StringBegin);
		char *String=(char*)malloc(Len+1);
		memcpy(String,StringBegin,Len);
		String[Len]=0;

		if (!pNode)
		{
			// find and/or create new root
			unsigned long Root;
			if (StringType!=BST_NORMAL)
				Root=0;
			else
			{
				Root=(unsigned char)*String;
#ifndef BLECH_CASE_SENSITIVE
				if (Root>='a' && Root<='z')
					Root-=32;
#endif
			}
			
//			if (BlechNode *pFound=FindNode(Root,String,StringType))
//				return pFound;
			BlechNode *pNew=AddNode(Root,String,StringType);
			free(String);
			return pNew;
		}
		else
		{
			// attach to this node

			// create new
			BlechNode *pNew=pNode->AddChild(String,StringType);
			free(String);
			return pNew;
		}
	}

	inline void Initialize()
	{
		BlechDebug("Initialize()");
		strcpy(Version,BLECHVERSION); // store version string always
		BlechDebug(Version);
		LastID=0;
		for (unsigned long N = 0 ; N < 256 ; N++)
		{
			Tree[N]=0;
		}
	}

	BlechNode *Tree[256];

//	std::map<std::string,PBLECHEVENTNODE> ExactMatch;

	BLECHEVENTMAP Event;

	unsigned long LastID;

	char PrintVarDelimiter;
	char ScanVarDelimiter;

	fBlechVariableValue VariableValue;
};



Posted: Wed Dec 08, 2004 3:50 am
by dont_know_at_all
That's because the nukepause event is missing a closing double quote.

Posted: Wed Dec 08, 2004 4:18 am
by dont_know_at_all
I can't find any situation that fails. With the latest zip, all the events seem to work as expected, assuming that the macro isn't broken.

If events are broken, I like to see a simple macro that shows the problem:

Code: Select all

#event myevent "string"

sub main
/echo something
/return

sub event_myevent(...)
/return

Posted: Wed Dec 08, 2004 7:02 am
by Cr4zyb4rd
I've given examples of the bugs in the various revisions and made Lax aware of them (via macros like you illustrated). I forget which one the lastest zip suffers from, but try with the three events I posted about above in this same thread that I took out of rogue helper...i *think* that was from the current blech.

Posted: Wed Dec 08, 2004 10:39 am
by Sequoyah
Thanks very much for the help. I've been over that afnuke.mac, afnuke.inc, and afnuke2.inc code until I'm turning purple. I didn't notice the quote problem. I'm looking forward to working on it when I get home and getting something stable. Again, thanks very much for your response. My gut was telling me that it was mostly the macro code or there would have been a lot more posts.

Sequoyah

Posted: Wed Dec 08, 2004 11:25 am
by A_Druid_00

Code: Select all

#Event SetXPCRadius     "[MQ2] SetPCRadius#*#"
#Event SetNPCRadius     "[MQ2] SetNPCRadius#*#"
Those 2 events would double fire for me when /echoed from the aliases:

Code: Select all

/squelch /alias /pcradius     /echo SetPCRadius
/squelch /alias /npcradius    /echo SetNPCRadius
in my druid mac. I got around it by changing the PCRadius event to XPCRadius. No big deal, since I know how to work around it, but I figured I'd put in the event that I had causing the double fire. I can't remember which of the two was causing it to fire double, but I believe it was /pcradius.

Posted: Wed Dec 08, 2004 2:31 pm
by dont_know_at_all
Are you sure you don't have two similar events? This never fails or double fires:

Code: Select all

#Event myevent1     "[MQ2] SetPCRadius#*#"
#Event myevent2     "[MQ2] SetNPCRadius#*#" 


Sub main
/if (!${Defined[counter1]}) {
    /declare counter1 int global 0
    /declare counter2 int global 0
} else {
    /varset counter1 0
    /varset counter2 0
}

    /echo SetPCRadius
    /echo SetNPCRadius
    /doevents
    /delay 1
    /echo counter1 ${counter1}
    /echo counter2 ${counter2}
/return

sub event_myevent1(string line)
    /varcalc counter1 ${counter1}+1
/return

sub event_myevent2(string line)
    /varcalc counter2 ${counter2}+1
/return

Posted: Wed Dec 08, 2004 3:00 pm
by A_Druid_00
This is what the events looked like. Every time I would use the alias /pcradius I would get a return from both subs. Doing /npcradius did not trigger a double fire, so that's when I had the idea to just change the PCRadius event to XPCRadius, which didn't end up firing both events.

Not sure if this helps at all, but the #Events and Sub Event_ are being called from a .inc and not the main .mac.

Code: Select all

Sub Event_SetNPCRadius(string Line) 
/if (${Line.Arg[3].Length}) { 
  /varset NPCRadius ${Line.Arg[3]} 
  /ini "${MyIni}" Settings NPCRadius ${Line.Arg[3]} 
} 
/echo I will go live when NPCs are within: ${NPCRadius} feet 
/return 

Sub Event_SetPCRadius(string Line) 
/if (${Line.Arg[3].Length}) { 
  /varset PCRadius ${Line.Arg[3]} 
  /ini "${MyIni}" Settings PCRadius ${Line.Arg[3]} 
} 
/echo I will AE Heal PCs within: ${PCRadius} feet 
/return 

Posted: Wed Dec 08, 2004 3:10 pm
by dont_know_at_all
Is it still exhibiting that behavior with the latest zip?

Posted: Wed Dec 08, 2004 3:13 pm
by A_Druid_00
To be honest dont_know, I don't know :D. I went back to the October zip after seeing that so many people had issues with the November one. I wasn't planning on recompiling again until after next week's patch, but if you think it'll help, I can try it out tonight.

Posted: Wed Dec 08, 2004 3:17 pm
by dont_know_at_all
Well, I want to get it fixed but I can't find any problems. Whenever you have spare time is fine...

Posted: Wed Dec 08, 2004 3:26 pm
by A_Druid_00
I'll try to screw around with it some before raids then, if not today, then tomorrow.