Initial commit.
This commit is contained in:
831
tools/ModView/genericparser.cpp
Normal file
831
tools/ModView/genericparser.cpp
Normal file
@@ -0,0 +1,831 @@
|
||||
// Main Parsing Class
|
||||
//
|
||||
|
||||
#if !defined(GENERICPARSER_H_INC)
|
||||
#include "GenericParser.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
//
|
||||
//
|
||||
// CParseGroup
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* CParseGroup
|
||||
* copy constructor. recursively copies all subgroups and pairs.
|
||||
*
|
||||
* Input
|
||||
* an existing parse group
|
||||
*
|
||||
* Output
|
||||
* none
|
||||
*
|
||||
************************************************************************************************/
|
||||
CParseGroup::CParseGroup(CParseGroup *orig)
|
||||
{
|
||||
CParseGroup *newGroup = 0;
|
||||
|
||||
if (orig == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mWriteable = orig->mWriteable;
|
||||
mName = orig->mName;
|
||||
mParent = orig->mParent;
|
||||
for (TParsePairIter itp = orig->PairsBegin(); itp != orig->PairsEnd(); itp++)
|
||||
{
|
||||
AddPair((*itp).first, (*itp).second);
|
||||
}
|
||||
for (TParseGroupIter itg = orig->GroupsBegin(); itg != orig->GroupsEnd(); itg++)
|
||||
{
|
||||
newGroup = new CParseGroup((*itg).second);
|
||||
AddSubGroup(newGroup);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* ~CParseGroup
|
||||
* basic destructor. deallocate any sub groups before going away
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* nothing
|
||||
************************************************************************************************/
|
||||
CParseGroup::~CParseGroup()
|
||||
{
|
||||
Clean();
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* FindPairValue
|
||||
* Return the value assigned to the provided key. If said key doesn't exist for this
|
||||
* ParseGroup, the provided default value is returned.
|
||||
*
|
||||
* inputs:
|
||||
* a key string to be used as an element in CParseGroup::mPairs
|
||||
* a default value string to be returned in the event that the provided key isn't found
|
||||
*
|
||||
* return:
|
||||
* either the string value stored at CParseGroup::mPairs[key] or, failing that, the provided
|
||||
* default value
|
||||
*
|
||||
************************************************************************************************/
|
||||
string CParseGroup::FindPairValue(string key, string defaultVal)
|
||||
{
|
||||
map<string, string>::iterator it;
|
||||
|
||||
it = mPairs.find(key);
|
||||
if (it != mPairs.end())
|
||||
{
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
return defaultVal;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* FindSubGroup
|
||||
* search for a subgroup with a particular name
|
||||
*
|
||||
* Input
|
||||
* name of subgroup, boolean indicating whether or not to search recursively
|
||||
*
|
||||
* Output
|
||||
* pointer to the desired subgroup, NULL if not found
|
||||
*
|
||||
************************************************************************************************/
|
||||
CParseGroup *CParseGroup::FindSubGroup(string name, bool recurse/*false*/)
|
||||
{
|
||||
TParseGroupIter it = mSubGroups.find(name);
|
||||
CParseGroup *subGroup = 0, *findGroup = 0;
|
||||
|
||||
if (it != mSubGroups.end())
|
||||
{
|
||||
return (*it).second;
|
||||
}
|
||||
|
||||
// didn't find it in the top level of groups. if we're supposed to recurse, search
|
||||
//our top level's subgroups, else return NULL
|
||||
if (recurse)
|
||||
{
|
||||
for (it = mSubGroups.begin(); it != mSubGroups.end(); it++)
|
||||
{
|
||||
subGroup = (*it).second;
|
||||
if (subGroup)
|
||||
{
|
||||
findGroup = subGroup->FindSubGroup(name, recurse);
|
||||
if (findGroup)
|
||||
{
|
||||
return findGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* FindSubGroupWithPair
|
||||
* finds a subgroup that contains the provided key/value pair
|
||||
*
|
||||
* inputs:
|
||||
* strings key and value for locating the subgroup
|
||||
*
|
||||
* return:
|
||||
* pointer to the ParseGroup representing the subgroup we're after or NULL if we didn't find it
|
||||
************************************************************************************************/
|
||||
CParseGroup *CParseGroup::FindSubGroupWithPair(string key, string value)
|
||||
{
|
||||
TParseGroupIter it;
|
||||
TParsePairIter itp;
|
||||
|
||||
for (it = mSubGroups.begin(); it != mSubGroups.end(); it++)
|
||||
{
|
||||
itp = ((CParseGroup*)(*it).second)->mPairs.find(key);
|
||||
if (itp != ((CParseGroup*)(*it).second)->mPairs.end())
|
||||
{
|
||||
if (value.compare((*itp).second) == 0)
|
||||
{
|
||||
// found a subgroup with a key/value pair matching the one we're looking for
|
||||
return ((CParseGroup*)(*it).second);
|
||||
}
|
||||
}
|
||||
}
|
||||
// none of our subgroups contains the key/value pair
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* DeleteSubGroup
|
||||
* find the given subgroup in our multimap of subgroups and remove it. also, try to find
|
||||
* it in our vector of ordered subgroups and remove it from there.
|
||||
*
|
||||
* Input
|
||||
* parse group to be deleted
|
||||
*
|
||||
* Output
|
||||
* true if it was found and deleted, false otherwise
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CParseGroup::DeleteSubGroup(CParseGroup *delGroup)
|
||||
{
|
||||
TParseGroupIter itg;
|
||||
|
||||
if (delGroup == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
itg = mSubGroups.find(delGroup->GetName());
|
||||
|
||||
if (itg != mSubGroups.end())
|
||||
{
|
||||
// this is a multimap, so make sure our pointers match
|
||||
while ( ((*itg).second != delGroup) && (itg != mSubGroups.end()) )
|
||||
{
|
||||
itg++;
|
||||
}
|
||||
if ((*itg).second == delGroup)
|
||||
{
|
||||
// try to find it in mInOrderSubGroups
|
||||
if (mInOrderSubGroups.size())
|
||||
{
|
||||
vector<pair<string, CParseGroup*> >::iterator itv = mInOrderSubGroups.begin();
|
||||
for (int i = 0; i < mInOrderSubGroups.size(); i++, itv++)
|
||||
{
|
||||
if (mInOrderSubGroups[i].second == delGroup)
|
||||
{
|
||||
mInOrderSubGroups.erase(itv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete delGroup;
|
||||
delGroup = 0;
|
||||
mSubGroups.erase(itg);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* Clean
|
||||
* cleans up our sub group list
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* nothing
|
||||
************************************************************************************************/
|
||||
void CParseGroup::Clean()
|
||||
{
|
||||
TParseGroupIter it;
|
||||
|
||||
for (it = mSubGroups.begin(); it != mSubGroups.end(); it++)
|
||||
{
|
||||
delete (CParseGroup*)(*it).second;
|
||||
}
|
||||
mSubGroups.clear();
|
||||
|
||||
mInOrderPairs.clear();
|
||||
mInOrderSubGroups.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* WriteLine
|
||||
* writes a line of data to the provided output string
|
||||
*
|
||||
* inputs:
|
||||
* a brace depth, allowing pretty formatted text, a line of text to be written, and an output string
|
||||
*
|
||||
* return:
|
||||
* true if data is written successfully, false otherwise
|
||||
************************************************************************************************/
|
||||
bool CParseGroup::WriteLine(int depth, const string line, string &output)
|
||||
{
|
||||
for (int i = 0; i < depth; i++)
|
||||
{
|
||||
output += "\t";
|
||||
}
|
||||
output += line;
|
||||
output += "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* WriteGroup
|
||||
* write this group's pairs and then its subgroups
|
||||
*
|
||||
* inputs:
|
||||
* name of the object, indentation depth, the destination string
|
||||
*
|
||||
* return:
|
||||
* true if data is written successfully, false otherwise
|
||||
************************************************************************************************/
|
||||
bool CParseGroup::WriteGroup(string name, int depth, string &output)
|
||||
{
|
||||
string curLine;
|
||||
CParseGroup *subGroup = 0;
|
||||
vector< pair<string, string> > &inOrderPairs = GetInOrderPairs();
|
||||
vector< pair<string, CParseGroup*> > &inOrderGroups = GetInOrderGroups();
|
||||
|
||||
// first, write out the name (e.g. "hook") of the object
|
||||
WriteLine(depth, name, output);
|
||||
|
||||
// now write out an open brace to begin the innards of our object
|
||||
WriteLine(depth, "{", output);
|
||||
|
||||
// write out the key/value pairs
|
||||
for (int p = 0; p < inOrderPairs.size(); p++)
|
||||
{
|
||||
curLine = "\"";
|
||||
curLine += inOrderPairs[p].first;
|
||||
curLine += "\"\t\"";
|
||||
curLine += inOrderPairs[p].second;
|
||||
curLine += "\"";
|
||||
WriteLine(depth+1, curLine, output);
|
||||
}
|
||||
|
||||
// recursively write out the subgroups
|
||||
for (int g = 0; g < inOrderGroups.size(); g++)
|
||||
{
|
||||
WriteLine(depth+1, "", output);
|
||||
subGroup = inOrderGroups[g].second;
|
||||
if (subGroup)
|
||||
{
|
||||
subGroup->WriteGroup(inOrderGroups[g].first, depth+1, output);
|
||||
}
|
||||
}
|
||||
|
||||
// now write out a close brace
|
||||
WriteLine(depth, "}", output);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
// CGenericParser
|
||||
//
|
||||
//
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* CGenericParser
|
||||
* constructor. inits the max token length.
|
||||
*
|
||||
* input:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* nothing
|
||||
************************************************************************************************/
|
||||
CGenericParser::CGenericParser():
|
||||
mMaxTokenLength(1024)
|
||||
{
|
||||
mLineCount = 0;
|
||||
mBraceDepth = 0;
|
||||
mCurGroup = NULL;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* ~CGenericParser
|
||||
* deallocates any CParseGroups we created, general clean up
|
||||
*
|
||||
* inputs:
|
||||
* none
|
||||
*
|
||||
* return:
|
||||
* nothing
|
||||
************************************************************************************************/
|
||||
CGenericParser::~CGenericParser()
|
||||
{
|
||||
mGroups.Clean();
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* SkipWhiteSpace
|
||||
* loops through the char's in data and points data to the next non-whitespace character. sets
|
||||
* newLine variable to true if one of the whitespace char's is a new line.
|
||||
*
|
||||
* input:
|
||||
* pointer to text data, pointer to a boolean which states whether or not a newline is encountered
|
||||
*
|
||||
* return:
|
||||
* the altered data pointer if it's pointing to a valid char. returns NULL if we reached the
|
||||
* end of the data.
|
||||
************************************************************************************************/
|
||||
char *CGenericParser::SkipWhiteSpace( char *data, bool *newLine )
|
||||
{
|
||||
char ch;
|
||||
|
||||
while(isspace(ch = *data))
|
||||
{
|
||||
if( '\n' == ch )
|
||||
{
|
||||
*newLine = true;
|
||||
mLineCount++;
|
||||
}
|
||||
data++;
|
||||
}
|
||||
if (0 == ch)
|
||||
{
|
||||
// reached the end of our data
|
||||
return NULL;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* EatCurrentLine
|
||||
* increments the data pointer until it hits a new line or we run out of char data
|
||||
*
|
||||
* input:
|
||||
* pointer to text data
|
||||
*
|
||||
* return:
|
||||
* nothing
|
||||
************************************************************************************************/
|
||||
void CGenericParser::EatCurrentLine( char **data )
|
||||
{
|
||||
while (**data && **data != '\n')
|
||||
{
|
||||
if ('{' == **data)
|
||||
{
|
||||
mBraceDepth++;
|
||||
}
|
||||
else if ('}' == **data)
|
||||
{
|
||||
if (0 == mBraceDepth)
|
||||
{
|
||||
// too many closing braces
|
||||
}
|
||||
else
|
||||
{
|
||||
mBraceDepth--;
|
||||
}
|
||||
}
|
||||
(*data)++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* GetToken
|
||||
* parses a text string to procure the next viable (non-whitespace, non-comment) token.
|
||||
* said token will be stored in CGenericParser::mToken
|
||||
*
|
||||
* input:
|
||||
* pointer to character data to be parsed, boolean stating whether or not new lines are
|
||||
* acceptable characters for the upcoming token
|
||||
*
|
||||
* return:
|
||||
* reference to the string containing the text value of the new token
|
||||
*
|
||||
************************************************************************************************/
|
||||
string &CGenericParser::GetToken( char **dataPtr, const bool allowNewLines )
|
||||
{
|
||||
char ch = 0;
|
||||
int len = 0;
|
||||
bool newLine = false;
|
||||
char *data = *dataPtr;
|
||||
|
||||
// reset our current token
|
||||
mToken = "";
|
||||
|
||||
// return an empty string if text data is NULL
|
||||
if ( !data )
|
||||
{
|
||||
*dataPtr = NULL;
|
||||
return mToken;
|
||||
}
|
||||
|
||||
// loop through the text data, skip whitespace, skip comments, get to the
|
||||
//beginning of the next token
|
||||
while ( data = SkipWhiteSpace( data, &newLine ) )
|
||||
{
|
||||
if ( newLine && !allowNewLines )
|
||||
{
|
||||
*dataPtr = data;
|
||||
return mToken;
|
||||
}
|
||||
|
||||
ch = *data;
|
||||
|
||||
// skip // comments
|
||||
if ( ('/' == ch) && ('/' == data[1]) )
|
||||
{
|
||||
EatCurrentLine(&data);
|
||||
}
|
||||
// skip /* */ comments
|
||||
else if ( ('/' == ch) && ('*' == data[1]) )
|
||||
{
|
||||
while ( *data && ((*data != '*') || (data[1] != '/')) )
|
||||
{
|
||||
data++;
|
||||
}
|
||||
if ( *data )
|
||||
{
|
||||
data += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if SkipWhiteSpace returned NULL, we got to the end of our data without finding
|
||||
//another valid token
|
||||
if ( !data )
|
||||
{
|
||||
*dataPtr = NULL;
|
||||
return mToken;
|
||||
}
|
||||
|
||||
//
|
||||
// at this point we're pointing at the next valid char in our data stream
|
||||
//
|
||||
|
||||
// handle quoted strings
|
||||
if ('\"' == ch)
|
||||
{
|
||||
data++;
|
||||
while (1)
|
||||
{
|
||||
ch = *data++;
|
||||
if (('\"' == ch) || !ch)
|
||||
{
|
||||
*dataPtr = (char*)data;
|
||||
return mToken;
|
||||
}
|
||||
if (len < mMaxTokenLength)
|
||||
{
|
||||
mToken.append(1,ch);
|
||||
len++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ok, these next characters are a token
|
||||
do
|
||||
{
|
||||
if ('{' == *data)
|
||||
{
|
||||
mBraceDepth++;
|
||||
}
|
||||
else if ('}' == *data)
|
||||
{
|
||||
if (0 == mBraceDepth)
|
||||
{
|
||||
// too many closing braces
|
||||
}
|
||||
else
|
||||
{
|
||||
mBraceDepth--;
|
||||
}
|
||||
}
|
||||
if (len < mMaxTokenLength)
|
||||
{
|
||||
mToken.append(1,ch);
|
||||
len++;
|
||||
}
|
||||
data++;
|
||||
ch = *data;
|
||||
if ( '\n' == ch )
|
||||
{
|
||||
mLineCount++;
|
||||
}
|
||||
} while (!isspace(ch));
|
||||
|
||||
if (len == mMaxTokenLength)
|
||||
{
|
||||
// token is too long...excess characters discarded
|
||||
len = 0;
|
||||
}
|
||||
|
||||
*dataPtr = ( char * ) data;
|
||||
return mToken;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* ReturnToBraceDepthZero
|
||||
* this function is called when a parse error is encountered. its goal is to eat any and all
|
||||
* text until it returns to brace depth zero, where the parser can hopefully start over
|
||||
*
|
||||
* inputs:
|
||||
* pointer to character data to be parsed
|
||||
*
|
||||
* return:
|
||||
* nothing
|
||||
************************************************************************************************/
|
||||
void CGenericParser::ReturnToBraceDepthZero(char **dataPtr)
|
||||
{
|
||||
// we already parsed a mismatched '}' so discount it in terms of subtracting from brace depth
|
||||
mBraceDepth++;
|
||||
|
||||
// commence the eating of tokens
|
||||
while (1)
|
||||
{
|
||||
GetToken(dataPtr);
|
||||
if ( (0 == mBraceDepth) || (mToken.empty()) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* ParseGroup
|
||||
* recursively parses a text string using a nested-block format. basically parses a pair of
|
||||
* tokens at once, if possible.
|
||||
*
|
||||
* inputs:
|
||||
* pointer to character data to be parsed
|
||||
*
|
||||
* return:
|
||||
* true if a group is parsed, false if end-of-file
|
||||
************************************************************************************************/
|
||||
bool CGenericParser::ParseGroup(char **dataPtr)
|
||||
{
|
||||
string tok1;
|
||||
string tok2;
|
||||
|
||||
while (1)
|
||||
{
|
||||
tok1 = GetToken(dataPtr);
|
||||
if (tok1.empty())
|
||||
{
|
||||
// reached end of data
|
||||
return false;
|
||||
}
|
||||
if ('}' == tok1[0])
|
||||
{
|
||||
// ending a ParseGroup
|
||||
mCurGroup = mCurGroup->GetParent();
|
||||
return true;
|
||||
}
|
||||
tok2 = GetToken(dataPtr);
|
||||
if (tok2.empty())
|
||||
{
|
||||
// empty group or a key-value pair with no value, just a key
|
||||
}
|
||||
else if ('{' == tok2[0])
|
||||
{
|
||||
// we're starting a new CParseGroup and its name is currently in tok1
|
||||
CParseGroup *newGroup = new CParseGroup(tok1, mCurGroup, mWriteable);
|
||||
if (NULL == mCurGroup)
|
||||
{
|
||||
// this is a top level group so add it to the parser's list
|
||||
mGroups.AddSubGroup(newGroup);
|
||||
mCurGroup = newGroup;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is somebody's subgroup
|
||||
mCurGroup->AddSubGroup(newGroup);
|
||||
// time for some ol' fashioned, down-home recursion. yeehaw!
|
||||
mCurGroup = newGroup;
|
||||
ParseGroup(dataPtr);
|
||||
}
|
||||
}
|
||||
else if ('}' == tok2[0])
|
||||
{
|
||||
// error. try to recover.
|
||||
ReturnToBraceDepthZero(dataPtr);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mCurGroup == 0)
|
||||
{
|
||||
// assume we're adding a key/value pair at the file level
|
||||
mGroups.AddPair(tok1, tok2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we're considering tok1 as a key and tok2 as a value
|
||||
mCurGroup->AddPair(tok1, tok2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************************************
|
||||
* Parse
|
||||
* parses text data for CParseGroup's until end-of-file is reached
|
||||
*
|
||||
* inputs:
|
||||
* pointer to character data to be parsed, boolean indicating if we should wipe our
|
||||
* stored data before parsing more, boolean indicating if we should make this data
|
||||
* writeable
|
||||
*
|
||||
* return:
|
||||
* nothing
|
||||
************************************************************************************************/
|
||||
bool CGenericParser::Parse(char **dataPtr, bool cleanFirst/*true*/, bool writeable /*false*/)
|
||||
{
|
||||
// a quick test to find hand-edit errors that always seem to manifest as perplexing bugs before we find them...
|
||||
{
|
||||
string strBraceTest(*dataPtr);
|
||||
int iOpeningBraces = 0;
|
||||
int iClosingBraces = 0;
|
||||
|
||||
char *p;
|
||||
|
||||
while ((p=strchr(strBraceTest.c_str(),'{'))!=NULL)
|
||||
{
|
||||
*p = '#'; // anything that's not a '{'
|
||||
iOpeningBraces++;
|
||||
}
|
||||
|
||||
while ((p=strchr(strBraceTest.c_str(),'}'))!=NULL)
|
||||
{
|
||||
*p = '#'; // anything that's not a '}'
|
||||
iClosingBraces++;
|
||||
}
|
||||
|
||||
if (iOpeningBraces != iClosingBraces)
|
||||
{
|
||||
// maybe print something here, but in any case...
|
||||
//
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (cleanFirst)
|
||||
{
|
||||
// if this is a new stream of data, init some stuff
|
||||
mGroups.Clean();
|
||||
}
|
||||
|
||||
mWriteable = writeable;
|
||||
mGroups.SetWriteable(mWriteable);
|
||||
|
||||
while (ParseGroup(dataPtr))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* Write
|
||||
* take all of the stuff we have stored as ParseGroups and write it in an aesthetically
|
||||
* pleasing form to an output string
|
||||
*
|
||||
* Input
|
||||
* output string
|
||||
*
|
||||
* Output
|
||||
* true if every parsegroup wrote without incident, false otherwise
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CGenericParser::Write(string &output)
|
||||
{
|
||||
string curLine;
|
||||
CParseGroup *subGroup = 0;
|
||||
vector< pair<string, string> > &inOrderPairs = mGroups.GetInOrderPairs();
|
||||
vector< pair<string, CParseGroup*> > &inOrderGroups = mGroups.GetInOrderGroups();
|
||||
|
||||
if (!mWriteable)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// write out the key/value pairs
|
||||
for (int p = 0; p < inOrderPairs.size(); p++)
|
||||
{
|
||||
curLine = "\"";
|
||||
curLine += inOrderPairs[p].first;
|
||||
curLine += "\"\t\"";
|
||||
curLine += inOrderPairs[p].second;
|
||||
curLine += "\"";
|
||||
mGroups.WriteLine(0, curLine, output);
|
||||
}
|
||||
|
||||
// recursively write out the subgroups
|
||||
for (int g = 0; g < inOrderGroups.size(); g++)
|
||||
{
|
||||
mGroups.WriteLine(0, "", output);
|
||||
subGroup = inOrderGroups[g].second;
|
||||
if (subGroup)
|
||||
{
|
||||
subGroup->WriteGroup(inOrderGroups[g].first, 0, output);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* AddParseGroup
|
||||
* if you want to be able to write out a parsegroup hierarchy, you may want to create
|
||||
* some of it yourself rather than just rely on what you've read in. that's what this
|
||||
* fn is for. this is returning a pointer to an object allocate on the heap, so make sure
|
||||
* it gets deallocated (if you add it into the existing hierarchy of a CGenericParser that
|
||||
* will take care of it for you)
|
||||
*
|
||||
* Input
|
||||
* name of the new parse group, parent of your new parse group (can't be NULL), whether
|
||||
* or not your new parse group will be writeable (defaults to true)
|
||||
*
|
||||
* Output
|
||||
* pointer to new parse group
|
||||
*
|
||||
************************************************************************************************/
|
||||
CParseGroup *CGenericParser::AddParseGroup(string groupName, CParseGroup &groupParent, bool writeable /*true*/)
|
||||
{
|
||||
CParseGroup *newGroup = new CParseGroup(groupName, &groupParent, writeable);
|
||||
|
||||
groupParent.AddSubGroup(newGroup);
|
||||
return newGroup;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* DeleteParseGroup
|
||||
* recursively deletes a parse group
|
||||
*
|
||||
* Input
|
||||
* parent of group to be deleted, pointer to parse group to be deleted
|
||||
*
|
||||
* Output
|
||||
* true if it was found and deleted
|
||||
*
|
||||
************************************************************************************************/
|
||||
bool CGenericParser::DeleteParseGroup(CParseGroup *parentGroup, CParseGroup *delGroup)
|
||||
{
|
||||
return parentGroup->DeleteSubGroup(delGroup);
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************************************
|
||||
* <function>
|
||||
*
|
||||
* inputs:
|
||||
*
|
||||
* return:
|
||||
*
|
||||
************************************************************************************************/
|
||||
#endif
|
||||
Reference in New Issue
Block a user