PCHAR ParseMacroParameter(PSPAWNINFO pChar, PCHAR szOriginal) { PCHARINFO pCharInfo = GetCharInfo(); if (!pCharInfo) return szOriginal; EnterMQ2Benchmark(bmParseMacroParameter); ParseMacroData(szOriginal); ExitMQ2Benchmark(bmParseMacroParameter); return (szOriginal); }
BOOL ParseMacroData(PCHAR szOriginal) { // find each {} PCHAR pBrace = strstr(szOriginal, "${"); if (!pBrace) return false; unsigned long NewLength; BOOL Changed = false; //PCHAR pPos; //PCHAR pStart; //PCHAR pIndex; CHAR szCurrent[MAX_STRING] = { 0 }; do { // find this brace's end PCHAR pEnd = &pBrace[1]; BOOL Quote = false; BOOL BeginParam = false; int nBrace = 1; while (nBrace) { ++pEnd; if (BeginParam) { BeginParam = false; if (*pEnd == '\"') { Quote = true; } continue; } if (*pEnd == 0) {// unmatched brace or quote goto pmdbottom; } if (Quote) { if (*pEnd == '\"') { if (pEnd[1] == ']' || pEnd[1] == ',') { Quote = false; } } } else { if (*pEnd == '}') { nBrace--; } else if (*pEnd == '{') { nBrace++; } else if (*pEnd == '[' || *pEnd == ',') BeginParam = true; } } *pEnd = 0; strcpy(szCurrent, &pBrace[2]); if (szCurrent[0] == 0) { goto pmdbottom; } if (ParseMacroData(szCurrent)) { unsigned long NewLength = strlen(szCurrent); memmove(&pBrace[NewLength + 1], &pEnd[1], strlen(&pEnd[1]) + 1); strncpy(pBrace, szCurrent, NewLength); pEnd = &pBrace[NewLength]; *pEnd = 0; } MQ2TYPEVAR Result; if (!ParseMQ2DataPortion(szCurrent, Result) || !Result.Type || !Result.Type->ToString(Result.VarPtr, szCurrent)) strcpy(szCurrent, "NULL"); NewLength = strlen(szCurrent); memmove(&pBrace[NewLength], &pEnd[1], strlen(&pEnd[1]) + 1); strncpy(pBrace, szCurrent, NewLength); Changed = true; pmdbottom:; } while (pBrace = strstr(&pBrace[1], "${")); if (Changed) while (ParseMacroData(szOriginal)) { } return Changed; }
VOID HideDoCommand(PSPAWNINFO pChar, PCHAR szLine, BOOL delayed) { if (delayed) { lockit lk(ghLockDelayCommand,"HideDoCommand"); CHAR szTheCmd[MAX_STRING]; strcpy_s(szTheCmd, szLine); PCHATBUF pChat = 0; try { pChat = new CHATBUF; strcpy_s(pChat->szText,szTheCmd); pChat->pNext = 0; if (!gDelayedCommands) { gDelayedCommands = pChat; } else { PCHATBUF pCurrent = 0; for (pCurrent = gDelayedCommands;pCurrent->pNext;pCurrent=pCurrent->pNext); pCurrent->pNext = pChat; } } catch(std::bad_alloc& exc) { UNREFERENCED_PARAMETER(exc); MessageBox(NULL,"HideDoCommand failed to allocate memory for gDelayedCommands","Did we just discover a memory leak?",MB_SYSTEMMODAL|MB_OK); }; return; } CAutoLock DoCommandLock(&gCommandCS); CHAR szTheCmd[MAX_STRING]; strcpy_s(szTheCmd, szLine); WeDidStuff(); CHAR szOriginalLine[MAX_STRING]; strcpy_s(szOriginalLine,szTheCmd); CHAR szArg1[MAX_STRING]; GetArg(szArg1,szTheCmd,1); std::string sName = szArg1; std::transform(sName.begin(), sName.end(), sName.begin(), tolower); if (mAliases.find(sName) != mAliases.end()) { sprintf_s(szTheCmd, "%s%s", mAliases[sName].c_str(), szOriginalLine + sName.size()); } GetArg(szArg1,szTheCmd,1); if (szArg1[0]==0) return; CHAR szParam[MAX_STRING]; strcpy_s(szParam, GetNextArg(szTheCmd)); if ((szArg1[0]==':') || (szArg1[0]=='{')) { bRunNextCommand = TRUE; return; } PMACROBLOCK pBlock = GetCurrentMacroBlock(); if (szArg1[0]=='}') { if (pBlock && pBlock->Line[pBlock->CurrIndex].LoopStart != 0) { pBlock->CurrIndex = pBlock->Line[pBlock->CurrIndex].LoopStart; extern void pop_loop(); pop_loop(); return; } if (strstr(szTheCmd,"{")) { GetArg(szArg1,szTheCmd,2); if (_stricmp(szArg1,"else")) { FatalError("} and { seen on the same line without an else present"); } // DebugSpew("DoCommand - handing {} off to FailIf"); if(pBlock) FailIf(pChar,"{",pBlock->CurrIndex,TRUE); } else { // handle this: // /if () { // } else /echo stuff GetArg(szArg1,szTheCmd,2); if (!_stricmp(szArg1,"else")) { // check here to fail this: // /if () { // } else // /echo stuff GetArg(szArg1,szTheCmd,3); if (!_stricmp(szArg1,"")) { FatalError("no command or { following else"); } bRunNextCommand = TRUE; } else { bRunNextCommand = TRUE; } } return; } if (szArg1[0]==';' || szArg1[0]=='[') { pEverQuest->InterpretCmd((EQPlayer*)pChar,szOriginalLine); return; } PMQCOMMAND pCommand=pCommands; while(pCommand) { if (pCommand->InGameOnly && gGameState!=GAMESTATE_INGAME) { pCommand=pCommand->pNext; continue; } int Pos=_strnicmp(szArg1,pCommand->Command,strlen(szArg1)); if (Pos<0) {// command not found break; } if (Pos==0) { if (pCommand->Parse && bAllowCommandParse) { pCommand->Function(pChar,ParseMacroParameter(pChar,szParam)); } else { pCommand->Function(pChar,szParam); } strcpy_s(szLastCommand,szOriginalLine); return; } pCommand=pCommand->pNext; } PBINDLIST pBind = pBindList; while( pBind ) { if( gGameState != GAMESTATE_INGAME ) { // Macro Binds only supported in-game pBind = pBind->pNext; continue; } int Pos = _strnicmp( szArg1, pBind->szName, strlen( szArg1 ) ); if( Pos == 0 ) { // found it! if( pBind->szFuncName ) { if( PCHARINFO pCharInfo = GetCharInfo() ) { std::string sCallFunc( pBind->szFuncName ); sCallFunc += " "; sCallFunc += szParam; CHAR szCallFunc[MAX_STRING] = { 0 }; strcpy_s(szCallFunc, sCallFunc.c_str()); ParseMacroData(szCallFunc, MAX_STRING); //Call(pCharInfo->pSpawn, (PCHAR)szCallFunc.c_str()); if (pBlock && !pBlock->BindCmd.size()) { if (!gBindInProgress) { gBindInProgress = true; pBlock->BindCmd = szCallFunc; } else { Beep(1000, 100); WriteChatf("Can't execute bind while another bind is on progress"); } } } } strcpy_s( szLastCommand, szOriginalLine ); return; } pBind = pBind->pNext; } // skip this logic for Bind Commands. if( _strnicmp( szOriginalLine, "sub bind_", 9 ) != 0 ) { if( !_strnicmp( szOriginalLine, "sub ", 4 ) ) { FatalError( "Flow ran into another subroutine. (%s)", szOriginalLine ); return; } strcpy_s( szLastCommand, szOriginalLine ); MacroError( "DoCommand - Couldn't parse '%s'", szOriginalLine ); } }
BOOL ParseMacroData(PCHAR szOriginal, SIZE_T BufferSize) { // find each {} PCHAR pBrace = strstr(szOriginal, "${"); if (!pBrace) return false; unsigned long NewLength; BOOL Changed = false; //PCHAR pPos; //PCHAR pStart; //PCHAR pIndex; CHAR szCurrent[MAX_STRING] = { 0 }; MQ2TYPEVAR Result = { 0 }; do { // find this brace's end PCHAR pEnd = &pBrace[1]; BOOL Quote = false; BOOL BeginParam = false; int nBrace = 1; while (nBrace) { ++pEnd; if (BeginParam) { BeginParam = false; if (*pEnd == '\"') { Quote = true; } continue; } if (*pEnd == 0) {// unmatched brace or quote goto pmdbottom; } if (Quote) { if (*pEnd == '\"') { if (pEnd[1] == ']' || pEnd[1] == ',') { Quote = false; } } } else { if (*pEnd == '}') { nBrace--; } else if (*pEnd == '{') { nBrace++; } else if (*pEnd == '[' || *pEnd == ',') BeginParam = true; } } *pEnd = 0; strcpy_s(szCurrent, &pBrace[2]); if (szCurrent[0] == 0) { goto pmdbottom; } if (ParseMacroData(szCurrent, sizeof(szCurrent))) { unsigned long NewLength = strlen(szCurrent); memmove(&pBrace[NewLength + 1], &pEnd[1], strlen(&pEnd[1]) + 1); int addrlen = (int)(pBrace - szOriginal); memcpy_s(pBrace, BufferSize - addrlen, szCurrent, NewLength); pEnd = &pBrace[NewLength]; *pEnd = 0; } ZeroMemory(&Result, sizeof(Result)); Result.Type = 0; Result.Int64 = 0; if (!ParseMQ2DataPortion(szCurrent, Result) || !Result.Type || !Result.Type->ToString(Result.VarPtr, szCurrent)) { strcpy_s(szCurrent, "NULL"); } NewLength = strlen(szCurrent); memmove(&pBrace[NewLength], &pEnd[1], strlen(&pEnd[1]) + 1); int addrlen = (int)(pBrace - szOriginal); memcpy_s(pBrace, BufferSize - addrlen, szCurrent, NewLength); if (bAllowCommandParse == false) { bAllowCommandParse = true; Changed = false; break; } else { Changed = true; } pmdbottom:; } while (pBrace = strstr(&pBrace[1], "${")); if (Changed) while (ParseMacroData(szOriginal, BufferSize)) { } return Changed; }
VOID Detour(PSPAWNINFO pChar, PCHAR szFullLine) { lockit lk(ghCCommandLock,"CCommandHook::Detour"); DebugSpew("CCommandHook::Detour(%s)",szFullLine); CHAR szFullCommand[MAX_STRING] = {0}; CHAR szCommand[MAX_STRING] = {0}; CHAR szArgs[MAX_STRING] = {0}; CHAR szOrig[MAX_STRING] = {0}; CHAR szSub[MAX_STRING] = {0}; std::string szSubFullCommand = ""; unsigned int k=0; bool OneCharacterSub = false; PSUB pSubLoop = pSubs; if (szFullLine[0]!=0) { strcpy_s(szFullCommand,szFullLine); GetArg(szCommand,szFullCommand,1); if (!_stricmp(szCommand,"/camp")) { if (GetmacroBlockCount()) { WriteChatColor("A macro is currently running. You may wish to /endmacro before you finish camping.", CONCOLOR_YELLOW ); } } szSubFullCommand = szFullCommand; size_t len = strnlen_s(szFullCommand, MAX_STRING); for (unsigned int i=0; i < sizeof(szFullCommand); i++ ) { if (szFullCommand[i] == '%' && ((i+2)<len)) { if (szFullCommand[i+2] == ' ' || szFullCommand[i+2] == '\0' || !isalnum(szFullCommand[i+2]) ) { if (szFullCommand[i+1] == 'm' || szFullCommand[i+1] == 'M' || szFullCommand[i+1] == 'o' || szFullCommand[i+1] == 'O' || szFullCommand[i+1] == 'p' || szFullCommand[i+1] == 'P' || szFullCommand[i+1] == 'r' || szFullCommand[i+1] == 'R' || szFullCommand[i+1] == 's' || szFullCommand[i+1] == 'S' || szFullCommand[i+1] == 't' || szFullCommand[i+1] == 'T' ) continue; else { szOrig[0] = szFullCommand[i+1]; szOrig[1] = '\0'; k = 1; OneCharacterSub = true; } } if (!OneCharacterSub) { for (unsigned int j=i+1; j < sizeof(szFullCommand); j++ ) { if (szFullCommand[j] == ' ' || szFullCommand[j] == '\0' ) break; else if (!isalnum(szFullCommand[j])) break; szOrig[k] = szFullCommand[j]; k++; } } while (pSubLoop) { if (!_stricmp(szOrig, pSubLoop->szOrig)) { sprintf_s( szSub, "%s", pSubLoop->szSub ); break; } pSubLoop = pSubLoop->pNext; } if (szSub[0] != '\0' ) { szSubFullCommand.replace(i,k+1,szSub); sprintf_s( szFullCommand, "%s",szSubFullCommand.c_str() ); } szOrig[0] = '\0'; szSub[0] = '\0'; k=0; OneCharacterSub = false; pSubLoop = pSubs; } } sprintf_s(szFullCommand, "%s", szSubFullCommand.c_str() ); std::string sName = szCommand; std::transform(sName.begin(), sName.end(), sName.begin(), tolower); if (mAliases.find(sName) != mAliases.end()) { sprintf_s(szCommand,"%s%s",mAliases[sName].c_str(),szFullCommand+sName.size()); strcpy_s(szFullCommand,szCommand); } GetArg(szCommand,szFullCommand,1); strcpy_s(szArgs, GetNextArg(szFullCommand)); PMQCOMMAND pCommand=pCommands; while(pCommand) { if (pCommand->InGameOnly && gGameState!=GAMESTATE_INGAME) { pCommand=pCommand->pNext; continue; } int Pos=_strnicmp(szCommand,pCommand->Command,strlen(szCommand)); if (Pos<0) {// command not found break; } if (Pos==0) { if (pCommand->Parse && bAllowCommandParse) { ParseMacroParameter(pChar, szArgs); } if (pCommand->EQ) { strcat_s(szCommand," "); strcat_s(szCommand,szArgs); Trampoline(pChar,szCommand); } else { pCommand->Function(pChar,szArgs); } strcpy_s(szLastCommand,szFullCommand); return; } pCommand=pCommand->pNext; } PBINDLIST pBind = pBindList; PMACROBLOCK pBlock = GetCurrentMacroBlock(); while( pBind ) { if( gGameState != GAMESTATE_INGAME ) { // Macro Binds only supported in-game pBind = pBind->pNext; continue; } int Pos = _strnicmp( szCommand, pBind->szName, strlen( szCommand ) ); if( Pos == 0 ) { // found it! if( pBind->szFuncName ) { if( PCHARINFO pCharInfo = GetCharInfo() ) { std::string sCallFunc( pBind->szFuncName ); sCallFunc += " "; sCallFunc += szArgs; CHAR szCallFunc[MAX_STRING] = { 0 }; strcpy_s(szCallFunc, sCallFunc.c_str()); ParseMacroData(szCallFunc, MAX_STRING); if (pBlock && !pBlock->BindCmd.size()) { if (!gBindInProgress) { gBindInProgress = true; pBlock->BindCmd = szCallFunc; } else { Beep(1000, 100); WriteChatf("Can't execute bind while another bind is on progress"); } } //CHAR szOrg[MAX_STRING] = {"${Time}"}; //ParseMacroData(szOrg, MAX_STRING); //WriteChatf("[%s] %s called",szOrg, szCallFunc.c_str()); //Beep(1000, 100); } } strcpy_s( szLastCommand, szFullCommand ); return; } pBind = pBind->pNext; } } Trampoline(pChar,szFullLine); strcpy_s(szLastCommand,szFullCommand); }