//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Implementation of CLogEvent // // $Workfile: $ // $Date: $ // //------------------------------------------------------------------------------------------------------ // $Log: $ // // $NoKeywords: $ //=============================================================================// #include #include #include #include "LogEvent.h" #include "util.h" #include "memdbg.h" //For debugging more than anything const char* CLogEvent::TypeNames[]= { {"No Type/Invalid!"}, {"Log File Initialize"}, {"Server Spawn"}, {"Server Shutdown"}, {"Log Closed"}, {"Server Misc"}, {"Server Name"}, {"Team Rename"}, {"Level Change"}, {"Cvar Assignment"}, {"Map CRC"}, {"Team Join"}, {"Connect"}, {"Enter game"}, {"Disconnect"}, {"Name Change"}, {"Frag!"}, {"Team frag!"}, {"Suicide!"}, {"Killed by world!"}, {"Build"}, {"Match Results Marker"}, {"Match Draw"}, {"Match Victor"}, {"Match Team Results"}, {"Talk"}, {"Team Talk"}, {"Cure"}, {"Named Goal Activated"}, {"Anon Goal Activated"}, {"Named Broadcast"}, {"Anon Broadcast"}, {"Change Class"}, }; //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::getArgument // Purpose: returns the iWhichArg'th argument // Input: iWhichArg - the desired argument // Output: const CLogEventArgument* //------------------------------------------------------------------------------------------------------ const CLogEventArgument* CLogEvent::getArgument(int iWhichArg) const { if (iWhichArg < m_args.size()) return m_args[iWhichArg]; else return NULL; } //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::parseArgs // Purpose: extracts the arguments out of the event text. //------------------------------------------------------------------------------------------------------ void CLogEvent::parseArgs() { char temp[512]; char* write=temp; const char* read=m_EventMessage; int i=0; while (*read) { if (*read == '\"') { //parseArgument moves the read pointer to the char after the closing " parseArgument(++read); *(write++)='['; *(write++)=(char)(i++)+48; //convert int to char by adding 48 *(write++)=']'; } else *write++=*read; *read++; } *write=0; Util::str2lowercase(temp,temp); m_StrippedText=new TRACKED char[strlen(temp)+1]; strcpy(m_StrippedText,temp); } //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::parseArgument // Purpose: helper function for parseArgs, this actually removes the argument // Input: raw - the string from which we want to remove the argument //------------------------------------------------------------------------------------------------------ void CLogEvent::parseArgument(const char*& raw) { char* atemp; if (!(atemp=strchr(raw,'\"'))) return; *atemp=0; //null out the closing " CLogEventArgument* newarg=new CLogEventArgument(raw); newarg->init(raw); m_args.push_back(newarg); *atemp='\"'; //restore it. raw=atemp; //advance the pointer } //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::keywordsOccur // Purpose: tests to see if all of the given keywords occur in the text for this event // Input: s1 - first keyword (required) // s2 - second keyword (optional) // s3 - third keyword (optional) // Output: Returns true if the event text contains all of the keywords passed in //------------------------------------------------------------------------------------------------------ bool CLogEvent::keywordsOccur(char* s1,char* s2,char* s3) { bool result=(strstr(m_StrippedText,s1)!=NULL); if (s2) { result = result && (strstr(m_StrippedText,s2)!=NULL); if (s3) { result = result && (strstr(m_StrippedText,s3)!=NULL); } } return result; } //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::determineType // Purpose: this is a big dumb if statement to determine the type of this event //------------------------------------------------------------------------------------------------------ //this is pretty cheesy void CLogEvent::determineType() { //for now just do this in a big dumb if statement if (keywordsOccur("killed","self","with")) m_EventType=SUICIDE; else if (keywordsOccur("log closed")) m_EventType=LOG_CLOSED; else if (keywordsOccur("server name is")) m_EventType=SERVER_NAME; else if (keywordsOccur("team name of")) m_EventType=TEAM_RENAME; else if (keywordsOccur("killed","by","world")) m_EventType=KILLED_BY_WORLD; else if (keywordsOccur("killed","(teammate)")) m_EventType=TEAM_FRAG; else if (keywordsOccur("killed","with")) m_EventType=FRAG; else if (keywordsOccur("say_team")) m_EventType=SAY_TEAM; else if (keywordsOccur("say")) m_EventType=SAY; else if (keywordsOccur("joined team")) m_EventType=TEAM_JOIN; else if (keywordsOccur("changed to team")) m_EventType=TEAM_JOIN; else if (keywordsOccur("log file started")) m_EventType=LOG_FILE_INIT; else if (keywordsOccur("spawning server")) m_EventType=SERVER_SPAWN; else if (keywordsOccur("connected","address")) m_EventType=CONNECT; else if (keywordsOccur("has entered the game")) m_EventType=ENTER_GAME; else if (keywordsOccur("disconnected")) m_EventType=DISCONNECT; else if (keywordsOccur("changed name to")) m_EventType=NAME_CHANGE; else if (keywordsOccur("built")) m_EventType=BUILD; else if (keywordsOccur("map crc")) m_EventType=MAP_CRC; else if (keywordsOccur("match","results","=------=")) m_EventType=MATCH_RESULTS_MARKER; else if (keywordsOccur("activated the goal")) m_EventType=NAMED_GOAL_ACTIVATE; else if (keywordsOccur("goal", "was activated")) m_EventType=ANON_GOAL_ACTIVATE; else if (keywordsOccur("named broadcast")) m_EventType=NAMED_BROADCAST; else if (keywordsOccur("broadcast")) m_EventType=ANON_BROADCAST; else if (keywordsOccur("changed class")) m_EventType=CLASS_CHANGE; else if (keywordsOccur("-> draw <-")) m_EventType=MATCH_DRAW; else if (keywordsOccur("defeated")) m_EventType=MATCH_VICTOR; else if (keywordsOccur("results")) m_EventType=MATCH_TEAM_RESULTS; else if (keywordsOccur("=")) m_EventType=CVAR_ASSIGN; else m_EventType=SERVER_MISC; } //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::CLogEvent // Purpose: CLogEvent constructor //------------------------------------------------------------------------------------------------------ CLogEvent::CLogEvent() :m_EventCode('\0'),m_EventTime(0),m_Valid(false),m_Next(NULL),m_StrippedText(NULL),m_EventType(INVALID),m_EventMessage(NULL) {} //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::~CLogEvent // Purpose: CLogEvent destructor //------------------------------------------------------------------------------------------------------ CLogEvent::~CLogEvent() { //this errors?! if (m_EventMessage) delete[] m_EventMessage; if (m_StrippedText) delete[] m_StrippedText; } //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::print // Purpose: debugging function, prints this event to a file // Input: f - the file to print to //------------------------------------------------------------------------------------------------------ void CLogEvent::print(FILE* f) { fprintf(f,"(%li) Event: %s\n",m_EventTime,m_EventMessage); } //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::CLogEvent // Purpose: CLogEvent constructor that reads an event from the specified file // Input: f - the file to read from //------------------------------------------------------------------------------------------------------ CLogEvent::CLogEvent(FILE* f) :m_EventCode('\0'),m_EventTime(0),m_Valid(false),m_Next(NULL),m_StrippedText(NULL),m_EventType(INVALID),m_EventMessage(NULL) { readEvent(f); } //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::readEvent // Purpose: reads an event by reading each part, then checking if it was successful // Input: f - the file to read from //------------------------------------------------------------------------------------------------------ void CLogEvent::readEvent(FILE* f) { m_Valid=true; if (m_Valid) readEventCode(f); if (m_Valid) readEventTime(f); if (m_Valid) readEventMessage(f); if (m_Valid) parseArgs(); if (m_Valid) determineType(); if (m_Valid) m_Valid=!feof(f); } //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::readEventCode // Purpose: reads the event code, the first character on the line (should be 'L') // Input: f - the file to read from //------------------------------------------------------------------------------------------------------ void CLogEvent::readEventCode(FILE* f) { fscanf(f," %c ",&m_EventCode); if (m_EventCode!='L') m_Valid=false; if (feof(f)) m_Valid=false; } //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::readEventMessage // Purpose: reads the text of the event message. // Input: f - the file to read from //------------------------------------------------------------------------------------------------------ void CLogEvent::readEventMessage(FILE* f) { char temp[512]; fgets(temp,512,f); //special case hack for broadcasts if (strncmp(temp,"Named Broadcast:",16)==0 || strncmp(temp,"Broadcast:",16)==0) { while(1) { fpos_t temp_pos; fgetpos(f,&temp_pos); CLogEvent cle(f); fseek(f,temp_pos,SEEK_SET); if (cle.isValid()) { //if the next log event is valid, then this broadcast did not span lines break; } else { temp[strlen(temp)-1]=' '; //rid ourselves of newline temp[strlen(temp)]=0; //rid ourselves of newline char buf[512]; fgets(buf,512,f); strcat(temp,buf); } } } if (feof(f)) { m_Valid=false; } else { temp[strlen(temp)-1]=0; //rid ourselves of newline m_EventMessage=new TRACKED char[strlen(temp)+1]; strcpy(m_EventMessage,temp); } } //------------------------------------------------------------------------------------------------------ // Function: CLogEvent::readEventTime // Purpose: reads and converts the time the event happened into a time_t // Input: f - the file to read from //------------------------------------------------------------------------------------------------------ void CLogEvent::readEventTime(FILE* f) { int month=-1,day=-1,year=-1; int hour=-1,minute=-1,second=-1; fscanf(f," %d/%d/%d - %d:%d:%d: ",&month,&day,&year,&hour,&minute,&second); if (month==-1 ||day==-1 ||year==-1 || hour==-1 || minute==-1 || second==-1) m_Valid=false; else if (feof(f)) m_Valid=false; else { tm t; t.tm_isdst=0; t.tm_hour=hour; t.tm_mday=day; t.tm_min=minute; t.tm_sec=second; t.tm_year=year-1900; //note no y2k prob here, so says the CRT manual //this allows values greater than 99, but it //just wants the input with 1900 subtracted. t.tm_mon=month-1; //jan = 0 m_EventTime=mktime(&t); } }