Moderator: MacroQuest Developers
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;
};


Code: Select all
#event myevent "string"
sub main
/echo something
/return
sub event_myevent(...)
/returnCode: Select all
#Event SetXPCRadius "[MQ2] SetPCRadius#*#"
#Event SetNPCRadius "[MQ2] SetNPCRadius#*#"
Code: Select all
/squelch /alias /pcradius /echo SetPCRadius
/squelch /alias /npcradius /echo SetNPCRadius
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
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

