summaryrefslogtreecommitdiff
path: root/utils/tfstats/textfile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/tfstats/textfile.cpp')
-rw-r--r--utils/tfstats/textfile.cpp405
1 files changed, 405 insertions, 0 deletions
diff --git a/utils/tfstats/textfile.cpp b/utils/tfstats/textfile.cpp
new file mode 100644
index 0000000..e8304fb
--- /dev/null
+++ b/utils/tfstats/textfile.cpp
@@ -0,0 +1,405 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implementation of CTextFile. See TextFile.h for details
+//
+// $Workfile: $
+// $Date: $
+//
+//------------------------------------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "TFStatsApplication.h"
+#include "util.h"
+#include "TextFile.h"
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::init
+// Purpose: initializes a CTextFile object
+// Input: filename - name of the file that this object will represent
+// eliminateComments - if true, C++ style comments will not be handed
+// back as tokens to the user of this object
+// Output:
+//------------------------------------------------------------------------------------------------------
+void CTextFile::init(const char* filename,bool eliminateComments)
+{
+ this->filename=filename;
+ //only support one push back
+ fWordPushed=false;
+ noComments=eliminateComments;
+ memset(wordBuf,0,BUF_SIZE);
+ theFile=fopen(filename,"rt");
+
+
+ //three different delim sets
+ //use this when reading strings
+ stringDelims="\"";
+ //use this when reading normal file stuff
+ normalDelims=" \t{}=\n\r;\"";
+ //use this when you want to discard a block
+ blockDelims="}";
+ //set to default
+ delims=normalDelims;
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::isDelim
+// Purpose: returns true if the given char is in the current delimiter set
+// Input: c - the character to test
+// Output: Returns true on success, false on failure.
+//------------------------------------------------------------------------------------------------------
+bool CTextFile::isDelim(char c)
+{
+ for (int i=0;delims[i] != 0; i++)
+ {
+ if (c==delims[i])
+ return true;
+ }
+ return false;
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::discardBlock
+// Purpose: advances the file ptr to the character after the next }
+//------------------------------------------------------------------------------------------------------
+void CTextFile::discardBlock()
+{
+ delims=blockDelims;
+ getToken();
+ delims=normalDelims;
+ discard("}");
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::getToken
+// Purpose: gets and returns the next token in the file
+// Output: const char*
+//------------------------------------------------------------------------------------------------------
+const char* CTextFile::getToken()
+{
+ return getToken(wordBuf);
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::getToken
+// Purpose: gets and returns the next token in the file, with an arbitrary buffer
+// Input: outputBuf - the buffer to put the token in
+// Output: const char*
+//------------------------------------------------------------------------------------------------------
+const char* CTextFile::getToken(char* outputBuf)
+{
+ if (fWordPushed)
+ {
+ fWordPushed=false;
+ strcpy(outputBuf,wordBuf);
+ return wordBuf;
+ }
+ readToken:
+ char c=getNextNonWSChar();
+ if (!theFile || feof(theFile)) return NULL;
+ if (isDelim(c) && !(isspace(c)))
+ {
+ outputBuf[0]=c;
+ outputBuf[1]=0;
+ return outputBuf;
+ }
+
+ int write=0;
+ while (!isDelim(c))
+ {
+ if (c=='\\')
+ {
+ c=fgetc(theFile);
+ if (!theFile&& feof(theFile))
+ break;
+ }
+
+ //these are both in the normal delimiter set, so this case won't happen unless we're reading a string
+ //which is exactly the behaviour we want
+ if (c=='\n' || c=='\r')
+ {
+ outputBuf[write]=0;
+ g_pApp->fatalError("new line in string constant (or unterminated string constant):\n\"%s\"",outputBuf);
+ }
+ outputBuf[write++]=c;
+ c=fgetc(theFile);
+
+ if (feof(theFile))
+ break;
+ }
+
+ if (theFile && !feof(theFile))
+ fseek(theFile,-1,SEEK_CUR); //seek to before the delimiter
+
+ outputBuf[write]=0;
+
+ if (outputBuf[0] == '/' && outputBuf[1] == '/')
+ {
+ while (fgetc(theFile)!='\n');
+ goto readToken;
+ }
+
+ return outputBuf;
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::getNextNonWSChar
+// Purpose: gets and returns the next non whitespace character
+// Output: char
+//------------------------------------------------------------------------------------------------------
+char CTextFile::getNextNonWSChar()
+{
+ char c;
+top:
+ c=' ';
+ while (theFile && !feof(theFile) && isspace(c))
+ c=fgetc(theFile);
+
+ if (!theFile) return 0;
+ if (feof(theFile)) return 0;
+
+ if (!noComments)
+ return c;
+
+ //check for comments
+ if (c=='/')
+ {
+ char c2=fgetc(theFile);
+ if (c2=='/') //found comment?
+ {
+ //discard and start over
+ getLine();
+ goto top;
+ }
+ else
+ {
+ fseek(theFile,-1,SEEK_CUR);
+ return c;
+ }
+ }
+ else
+ {
+ return c;
+ }
+
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::readString
+// Purpose: reads and returns the contents of the file up to the next "
+// Output: const char*
+//------------------------------------------------------------------------------------------------------
+const char* CTextFile::readString()
+{
+ if (fWordPushed)
+ {
+ fWordPushed=false;
+ return wordBuf;
+ }
+ char c=getNextNonWSChar();
+
+ if (c=='\"')
+ {
+ delims=stringDelims;
+ getToken(); //handles escaping stuff
+ delims=normalDelims;
+ if (wordBuf[0]=='\"' && wordBuf[1]==0)
+ wordBuf[0]=0;
+ else
+ discard("\"");
+ }
+ else
+ {
+ fseek(theFile,-1,SEEK_CUR);
+ getToken();
+ }
+
+
+ return wordBuf;
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::readString
+// Purpose: reads and returns the contents of the file up to the next "
+// Output: const char*
+//------------------------------------------------------------------------------------------------------
+const char* CTextFile::readString(char* buf)
+{
+ if (fWordPushed)
+ {
+ fWordPushed=false;
+ strcpy(buf,wordBuf);
+ return buf;
+ }
+ char c=getNextNonWSChar();
+ if (eof()) return NULL;
+ if (c=='\"')
+ {
+ delims=stringDelims;
+ getToken(buf); //handles escaping stuff
+ delims=normalDelims;
+ if (buf[0]=='\"' && buf[1]==0)
+ buf[0]=0;
+ else
+ discard("\"");
+ }
+ else
+ {
+ fseek(theFile,-1,SEEK_CUR);
+ getToken(buf);
+ }
+
+
+ return buf;
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::getLine
+// Purpose: reads and returns the contents of the file up to the next \r or \n
+// Output: const char*
+//------------------------------------------------------------------------------------------------------
+const char* CTextFile::getLine()
+{
+ fgets(wordBuf,BUF_SIZE,theFile);
+ return wordBuf;
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::discard
+// Purpose: discards the next token, also checks to see if it is the same as the token
+// the user of the object was expecting to discard.
+// Input: test - the token that is expected to be discarded.
+// Output: Returns true on success, false on failure.
+//------------------------------------------------------------------------------------------------------
+bool CTextFile::discard(char* test)
+{
+ if (!theFile || feof(theFile))
+ return true;
+
+ char wordBuf2[BUF_SIZE];
+ getToken(wordBuf2);
+
+ int result = stricmp(wordBuf2,test);
+ if (result !=0)
+ g_pApp->fatalError("While parsing %s, expecting \"%s\", got \"%s\"",filename.c_str(),test,wordBuf2);
+
+ return true;
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::peekNext
+// Purpose: peeks at the next token. gets then immediately pushes it back
+// destroys any pushed back words from before.
+// Output: char*
+//------------------------------------------------------------------------------------------------------
+char* CTextFile::peekNext()
+{
+ fpos_t startpos;
+ fgetpos(theFile,&startpos);
+
+ const char* c=getToken(peekBuf);
+ if (!c)
+ return NULL;
+ //pushBack(c);
+ fseek(theFile,startpos,SEEK_SET);
+ return peekBuf;
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::peekNextString
+// Purpose: peeks at the next string. gets then immediately pushes it back
+// destroys any pushed back words from before.
+// Output: char*
+//------------------------------------------------------------------------------------------------------
+char* CTextFile::peekNextString()
+{
+ if (!theFile)
+ return NULL;
+ fpos_t startpos;
+ fgetpos(theFile,&startpos);
+
+
+ const char* c=readString(peekBuf);
+ if (!c)
+ return NULL;
+ //pushBack(c);
+ fseek(theFile,startpos,SEEK_SET);
+ return peekBuf;
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::pushBack
+// Purpose: "pushes" a token back into the stream. Only can have one pushed back
+// token at a time. getting a token or peeking will destroy the pushed back token
+// Input: pushTok - the token to push back.
+//------------------------------------------------------------------------------------------------------
+void CTextFile::pushBack(const char* pushTok)
+{
+ if (pushTok != wordBuf)
+ strncpy(wordBuf,pushTok,BUF_SIZE);
+ fWordPushed=true;
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::reset
+// Purpose: resets the file ptr to the beginning of the file
+//------------------------------------------------------------------------------------------------------
+void CTextFile::reset()
+{
+ fseek(theFile,0,SEEK_SET);
+}
+
+//------------------------------------------------------------------------------------------------------
+// Function: CTextFile::~CTextFile
+// Purpose: destructor
+//------------------------------------------------------------------------------------------------------
+CTextFile::~CTextFile()
+{
+ if (theFile)
+ fclose(theFile);
+#ifndef WIN32
+ chmod(filename.c_str(),PERMIT);
+#endif
+
+}
+
+
+
+bool CTextFile::eof()
+{
+ bool retval=false;
+
+ //test current pos first
+ retval = (!theFile || feof(theFile));
+ if (retval)
+ return true;
+
+ //now see if only whitespace is left
+
+ fpos_t beforecheck;
+ fgetpos(theFile,&beforecheck);
+ char c=getNextNonWSChar();
+
+ retval = (!theFile || feof(theFile));
+
+ fseek(theFile,beforecheck,SEEK_SET);
+ return retval;
+}
+
+
+int CTextFile::readInt()
+{
+ readString();
+ return atoi(wordBuf);
+}
+
+unsigned long CTextFile::readULong()
+{
+ readString();
+ return strtoul(wordBuf,NULL,10);
+} \ No newline at end of file