// parsegame.cpp Game-specific parsing functions #include "parsegame.h" /******************************************************************************* // FUNCTION NAME: GetGameInfo // // DESCRIPTION OF FUNCTION: Checks each record in the Game Section of a BAM // file for errors and stores the records into GameList // // DESCRIPTION OF ALGORITHM: While AnotherRecord returns true, calls ReadRecord // to pull record data into a string, CheckGameRecord to parse it, and // GameListType::insert to store it into the list. When AnotherRecord returns // false, if no errors were discovered, calls WriteNoErrors. Always calls // WriteSectionFooter just before returning // // CALLED BY: ParseFile // CALLS: WriteSectionHeader,WriteNoErrors,WriteSectionFooter,AnotherRecord, // ReadRecord,CheckGameRecord,GameListType::insert, // GameListType::smallestIndex // // PARAMETERS: / inout / inputFile - input filestream that has been opened to // the appropriate BAM data file // / inout / outputFile - output filestream that has been opened to // the appropriate BAC error file // / in / FileName - string that contains the name of the BAM file // / out / GameList - GameListType to hold the records stored in // the BAM data file // // PRECONDITIONS: inputFile has been properly intialized to the appropriate // BAM file, and outputFile has been proprely initalized to the appropriate // BAC file. // // POSTCONDITIONS: The games section has been removed from the input file, // any errors located in the section were written to the output file, // all records that were in the section of the BAM file have been stored into // the list // // AUTHOR: Amy Langill *2B DATE: 3/28/1999 *******************************************************************************/ void GetGameInfo(ifstream& inputFile,ofstream& outputFile,string FileName, GameListType& GameList,AlleyListType& AlleyList, EventListType& EventList,ToolsListType& ToolsList, ConditionsListType& ConditionsList) { // Functions called only by GetGameInfo bool CheckGameRecord(string& dataString,ofstream& errorFile, GameRecord& record,bool& errorFound,int& lineNumber, int recordCounter,int minIndex,AlleyListType& AlleyList, EventListType& EventList,ToolsListType& ToolsList, ConditionsListType& ConditionsListType); // Variables declared within GetGameInfo: bool notDoneYet=false; // Are we done yet? bool errorsFound=false; // Have any errors been encountered in the file? string recordData; // To hold record data pulled from file GameRecord tempRecord; // To hold data before storing in list BALSectionType section=GAME; // Keep track of which section we're in int recordCounter=0; // Keep track of how many records have been parsed int lineCounter=0; // Keep track of what line of input file we're on int recIndex; // Create an index for each record inputFile.ignore(200,'\n'); // Skip label line of input file WriteSectionHeader(outputFile,FileName,section); // Write section Label notDoneYet=AnotherRecord(inputFile); // not done if there's another record while (notDoneYet) // As long as there's another record { recordCounter++;lineCounter++; // duh... increment the counters recIndex=(GameList.smallestIndex()-1); // find default index // Read the record, parse it, insert into the list ReadRecord(inputFile,recordData,section); if (CheckGameRecord(recordData,outputFile,tempRecord,errorsFound,lineCounter, recordCounter,recIndex,AlleyList,EventList,ToolsList, ConditionsList)) GameList.insert(tempRecord); // Don't insert if there's a prob w/indexes if (AnotherRecord(inputFile)) // If there's more in the file, { inputFile.ignore(200,'\n'); // Skip the record delimiter tempRecord.Reset(); // Reset record for next bunch o' data } else notDoneYet=false; } // end of the while-loop if (!errorsFound) // If there weren't any errors, say so WriteNoErrors(outputFile); WriteSectionFooter(outputFile); // Write section delimiter line return; } /******************************************************************************* // FUNCTION NAME: CheckGameRecord // // DESCRIPTION OF FUNCTION: Parses Game record data as stored in dataString, // writes any errors contained therein to the specified errorFile, and stores // valid data values into record. // // DESCRIPTION OF ALGORITHM: For each field in the record, pulls the field // label off the front dataString and compares it to the define field label // with GameRecord::FieldLabel and calls WriteLabeError if necessary, then // pulls the data off the front of dataString, stores it into record, and // checks to see if the field now contains a valid value. If the field is // invalid, the function calls WriteDataError. If the index is invalid, // the function assigns a default index to the record. // // CALLED BY: GetGameInfo // CALLS: WriteLabelError,WriteDataError,GameRecord::FieldLabel, // GameRecord::FieldWidth,GameRecord::NewIndex,GameRecord::Reset, // GameRecord::fieldOK,CheckGameReference // // PARAMETERS: / in / dataString - string that holds record data // / inout / errorFile - ofstream for BAC error report // / out / record - GameRecordType for storing data // / inout / errorFound - Show whether any errors have been found // in the BAM file // / inout / lineNumber - The line of the BAM file a field shows // up on // / in / recordCounter - The number of this record in the BAM file // / in / minIndex - A default index to be used if the one in the // BAM file is invalid // // PRECONDITIONS: dataString contains an entire record of data, with the labels // and data separated by spaces. errorFile has been properly initalized to the // appropriate error file. // // POSTCONDITIONS: The record is checked, stored, and any applicable errors are // written to the errorFile filestream. Returns false if the record referenced // non-existent parent indexes in other tables and true otherwise. // // AUTHOR: Amy Langill *2B DATE: 3/28/1999 *******************************************************************************/ bool CheckGameRecord(string& dataString,ofstream& errorFile, GameRecord& record,bool& errorFound,int& lineNumber, int recordCounter,int minIndex,AlleyListType& AlleyList, EventListType& EventList,ToolsListType& ToolsList, ConditionsListType& ConditionsList) { bool CheckGameReference(GameRecord record,GameFieldType fld, AlleyListType& Alleys,EventListType& Events, ToolsListType& Tools,ConditionsListType& Conditions); DataErrorType currentError; // Tracking what error has occurred GameFieldType currFld; // For iterating through the whole record string fieldData; // Data for a specific field string fieldLabel; // Label for a specific field bool OKToInsert=true; // Were there problems with indexes? // Check each field in the record against its limits for (currFld=G_GDEX;currFld<=G_SPARE;currFld=GameFieldType(currFld+1)) { // Pull the label off the front of the record string: fieldLabel=dataString.substr(0,(dataString.find(" ",0)+1)); dataString.erase(0,(fieldLabel.length())); if (fieldLabel!=record.FieldLabel(currFld)) // If the label's wrong { WriteLabelError(errorFile,errorFound,fieldLabel, record.FieldLabel(currFld),recordCounter, lineNumber); errorFound=true; } // Pull the data off the front of the record string fieldData=dataString.substr(0,record.FieldWidth(currFld)); dataString.erase(0,(record.FieldWidth(currFld)+1)); record.Update(fieldData,currFld); // Store into the record currentError = record.fieldOK(currFld); // Check the Record if (currentError!=NO_PROB) // If something's wrong { WriteDataError(errorFile,currentError,errorFound, record.FieldContains(currFld),record.FieldLabel(currFld), recordCounter,lineNumber); errorFound = true; record.Reset(currFld); } if ((currentError==INDEX_RANGE_ERR)&&(currFld==G_GDEX)) // Index negative record.NewIndex(minIndex); } // Make sure the indexes that point to other tables are OK for (currFld=G_ADEX;currFld<=G_CDEX;currFld=GameFieldType(currFld+1)) { if (!CheckGameReference(record,currFld,AlleyList,EventList,ToolsList, ConditionsList)) { WriteDataError(errorFile,INDEX_EXIST_ERR,errorFound, record.FieldContains(currFld),record.FieldLabel(currFld), recordCounter,lineNumber); errorFound = true; OKToInsert=false; } } return OKToInsert; // If it contains bad indexes, don't store it } /******************************************************************************* // FUNCTION NAME: CheckGameReference // // DESCRIPTION OF FUNCTION: Determines if the references the game record makes // to earlier tables are valid ones. // // DESCRIPTION OF ALGORITHM: Converts the index in the current field to an int // and depending on the value of fld, calls the getRecord function of that list // type. If the getNext fails, returns false. Returns true otherwise. // // CALLED BY: CheckGameRecord // CALLS: AlleyListType::getRecord,EventListType::getRecord, // ToolsListType::getRecord,ConditionsListType::getRecord, // GameRecord::FieldContains, // // PARAMETERS: / in / record - GameRecord that contains the index references // being checked // / in / fld - GameFieldType that specifies which field of the // record is being tested // / in / Alleys - AlleyList that contains the alley records // against which record is being checked // / in / Events - EventList that contains the event records // against which the record is being checked // / in / Tools - ToolsList that contains the tools records that // record is being checked against // / in / Conditions - ConditionsList that contains the // conditions records for checking record with // // PRECONDITIONS: record.adex,record.edex,record.tdex,record.cdex have been // initialized to meaningful values and fld is one of {G_ADEX,G_EDEX,G_TDEX, // G_CDEX}. // // POSTCONDITIONS: Returns true if the index stored in the specified field was // found in the corresponding table. // // AUTHOR: Amy Langill *2B DATE: 4/3/1999 *******************************************************************************/ bool CheckGameReference(GameRecord record,GameFieldType fld, AlleyListType& Alleys,EventListType& Events, ToolsListType& Tools,ConditionsListType& Conditions) { AlleyListPtr Aptr; // For searching Alleys EventListPtr Eptr; // For searching Events ToolsListPtr Tptr; // For searching Tools ConditionsListPtr Cptr; // For searching Conditions int index; // For converting from string to int bool indexExists=true; // Was the index found? index = atoi(record.FieldContains(fld).c_str()); // Convert string to int switch (fld) // Search the appropriate table for the index value { case G_ADEX: indexExists = Alleys.getRecord(index,Aptr); break; case G_EDEX: indexExists = Events.getRecord(index,Eptr); break; case G_TDEX: indexExists = Tools.getRecord(index,Tptr); break; case G_CDEX: indexExists = Conditions.getRecord(index,Cptr); break; } return indexExists; // Was the index found? }