/***************************************************************************** # Copyright (C) 1994-2008 by David Gordon. # All rights reserved. # # This software is part of a beta-test version of the Consed/Autofinish # package. It should not be redistributed or # used for any commercial purpose, including commercially funded # sequencing, without written permission from the author and the # University of Washington. # # This software is provided ``AS IS'' and any express or implied # warranties, including, but not limited to, the implied warranties of # merchantability and fitness for a particular purpose, are disclaimed. # In no event shall the authors or the University of Washington be # liable for any direct, indirect, incidental, special, exemplary, or # consequential damages (including, but not limited to, procurement of # substitute goods or services; loss of use, data, or profits; or # business interruption) however caused and on any theory of liability, # whether in contract, strict liability, or tort (including negligence # or otherwise) arising in any way out of the use of this software, even # if advised of the possibility of such damage. # # Building Consed from source is error prone and not simple which is # why I provide executables. Due to time limitations I cannot # provide any assistance in building Consed. Even if you do not # modify the source, you may introduce errors due to using a # different version of the compiler, a different version of motif, # different versions of other libraries than I used, etc. For this # reason, if you discover Consed bugs, I can only offer help with # those bugs if you first reproduce those bugs with an executable # provided by me--not an executable you have built. # # Modifying Consed is also difficult. Although Consed is modular, # some modules are used by many other modules. Thus making a change # in one place can have unforeseen effects on many other features. # It may takes months for you to notice these other side-effects # which may not seen connected at all. It is not feasable for me to # provide help with modifying Consed sources because of the # potentially huge amount of time involved. # #*****************************************************************************/ #include "parseUserDefinedTagTypeLine.h" #include "rwctokenizer.h" #include "userDefinedTagFieldType.h" #include "userDefinedTagField.h" #include "bIsNumericLongMaybeWithWhitespace.h" #include "bIsNumericDouble.h" #include "consed.h" #include "tag.h" #include "consedParameters.h" #include "tagTypes.h" #include "bIsNumericMaybeWithWhitespace.h" // This routine is used by both readPHD and parseAceFile. That way if // there is any change, the change needs only be made in this one // place. However, both readPHD and parseAceFile have separate // routines for reading, since they have separate file pointers and // they separately keep track of the file name (for errors) and the // line. When there is an error, this information must be presented // to the user. A simple way of implementing this would be to read // the line in readPHD/parseAceFile, call this to parse the line and // pass back an error message. Thus if there were any problem reading // or parsing the file, that error could be handled in // readPHD/parseAceFile. However, in the case of string field, this // routine wants to read additional lines to complete the string field. // Thus it needs a routine to read additional lines. To do that, I // have it call a routine, myFgetsOrParsePanic, which exists in the // readPHD/parseAceFile parent. Thus it can use the right file // pointer and keep track of line numbers and anything else the parent // wants for reading from the file. To do this, I pass myFgetsOrParsePanic's // pointer as an argument to this routine. #define PARSE_PANIC( soErrorMessage ) \ myParsePanic( soErrorMessage, __LINE__, __FILE__ ); #define FGETS_OR_PARSE_PANIC( soErrorMessage ) \ myFgetsOrParsePanic( soErrorMessage, __LINE__, __FILE__, szLine ); static RWCString soUserDefinedTypeLineMessage( "User defined tags have fields that are of the form:\n(field name) (value)\nin all cases except string fields in which case the field is of the form:\n(field name) (number of lines of text){\n" ); void parseUserDefinedTagTypeLine( char* szLine, userDefinedTagType* pUserDefinedTagType, userDefinedTagField*& pUserDefinedTagField, int& nIndexOfNextUserDefinedField, PARSE_PANIC_FUNCTION myParsePanic, FGETS_OR_PARSE_PANIC_FUNCTION myFgetsOrParsePanic ) { RWCString soLine( szLine ); RWCTokenizer tok( soLine ); RWCString soFieldNameOnLine = tok(); // let's see if it matches the expected userDefinedTagFieldType* pUserDefinedTagFieldType = pUserDefinedTagType->aUserDefinedTagFieldType_[ nIndexOfNextUserDefinedField ]; if ( soFieldNameOnLine != pUserDefinedTagFieldType->soFieldName_ ) { // ok, find the next userDefinedTagFieldType that does match bool bFound = false; for( int nIndex = nIndexOfNextUserDefinedField + 1; nIndex < pUserDefinedTagType->aUserDefinedTagFieldType_.length() && !bFound; ++nIndex ) { pUserDefinedTagFieldType = pUserDefinedTagType->aUserDefinedTagFieldType_[ nIndex ]; if ( soFieldNameOnLine == pUserDefinedTagFieldType->soFieldName_ ) { bFound = true; nIndexOfNextUserDefinedField = nIndex; } } if ( !bFound ) { RWCString soErrorMessage = soUserDefinedTypeLineMessage + " could not recognize userDefinedTagFieldType " + soFieldNameOnLine + " or it is out of order in line " + soLine; PARSE_PANIC( soErrorMessage ); } } // if ( soFieldNameOnLine != // when reached here, pUserDefinedTagFieldType contains a pointer // to the field type on the line, and // nIndexOfNextUserDefinedTagFieldType is ready to be returned. // Must parse the rest of this field. if ( pUserDefinedTagFieldType->eFieldType_ == userDefinedTagFieldType::eInteger ) { // CT{ // Contig1 userTag1 consed 193 193 040115:154221 // joeint 5 // joeint 7 // joestring 3{ // This is line1 of 3 // This is line2 of 3 // This is line3 of 3 // C} // joestring 1{ // This is line1 of 1 // C} // joefloat 1.7 // joesmoke 27 // joesmoke 32 // } pUserDefinedTagField = new userDefinedIntegerTagField(); RWCString soInteger = tok(); if ( !bIsNumericLongMaybeWithWhitespace( soInteger, ((userDefinedIntegerTagField*) pUserDefinedTagField)->l_ ) ) { RWCString soErrorMessage = soFieldNameOnLine + " is specified in the file " + pCP->filFileOfTagTypes_ + " to be an integer field so this line should look like this:\n" + soFieldNameOnLine + ": (number)\n" + " but instead of a number there is " + soInteger; PARSE_PANIC( soErrorMessage ); } } else if ( pUserDefinedTagFieldType->eFieldType_ == userDefinedTagFieldType::eFloating ) { pUserDefinedTagField = new userDefinedFloatingTagField(); RWCString soFloating = tok(); if ( !bIsNumericDouble( soFloating, ( (userDefinedFloatingTagField*) pUserDefinedTagField)->d_ ) ) { RWCString soErrorMessage = soFieldNameOnLine + " is specified in the file " + pCP->filFileOfTagTypes_ + " to be a floating point field so this line should look like this:\n" + soFieldNameOnLine + ": (number)\n" + " but instead of a number there is " + soFloating; PARSE_PANIC( soErrorMessage ); } } else if ( pUserDefinedTagFieldType->eFieldType_ == userDefinedTagFieldType::eString ) { pUserDefinedTagField = new userDefinedStringTagField(); // looks like this: // joestring 3{ // This is line1 of 3 // This is line2 of 3 // This is line3 of 3 // S} RWCString soNumberOfLines = tok(); if ( soNumberOfLines.cGetLastChar() != '{' ) { RWCString soErrorMessage = soFieldNameOnLine + " is specified in the file " + pCP->filFileOfTagTypes_ + " to be a string field so this line should look like this:\n" + soFieldNameOnLine + " (number of lines){\n" + " but the { is missing and instead this line contains: " + soLine; PARSE_PANIC( soErrorMessage ); } soNumberOfLines.removeLastChar(); int nNumberOfLines; if ( !bIsNumericMaybeWithWhitespace( soNumberOfLines, nNumberOfLines ) ) { RWCString soErrorMessage = soFieldNameOnLine + " is specified in the file " + pCP->filFileOfTagTypes_ + " to be a string field so this line should look like this:\n" + soFieldNameOnLine + " (number of lines){\n" + " but the last field which should be a number is instead " + soNumberOfLines + " and the whole line is:\n" + soLine; PARSE_PANIC( soErrorMessage ); } // so read nNumberOfLines more and then read the "S}" line for( int nLine = 0; nLine < nNumberOfLines; ++nLine ) { FGETS_OR_PARSE_PANIC( "premature end of file while in the middle of a string tag field" ); ((userDefinedStringTagField*)pUserDefinedTagField)->so_ += szLine; } // remove the final CR on input so that strings that // are only one line will have no CR's in them ((userDefinedStringTagField*)pUserDefinedTagField)->so_.removeFinalCR(); FGETS_OR_PARSE_PANIC( "premature end of file while at the end of a string tag field" ); if ( ! ( szLine[0] == 'S' && szLine[1] == '}' ) ) { RWCString soErrorMessage = soFieldNameOnLine + " is specified in the file " + pCP->filFileOfTagTypes_ + " to be a string field so this line should look like this:\n" + soFieldNameOnLine + " (number of lines){\n" + " followed by " + soNumberOfLines + " lines of text followed by\n" + "S}\n" + " but the S} is missing"; cerr << "should have been S} szLine = " << szLine << endl; PARSE_PANIC( soErrorMessage ); } } else if ( pUserDefinedTagFieldType->eFieldType_ == userDefinedTagFieldType::ePointer ) { // joesmoke 32 // } pUserDefinedTagField = new userDefinedPointerTagField(); RWCString soTagID = tok(); long lTagID; if ( !bIsNumericLongMaybeWithWhitespace( soTagID, lTagID ) ) { RWCString soErrorMessage = soFieldNameOnLine + " is specified in the file " + pCP->filFileOfTagTypes_ + " to be a pointer field so this line should look like this:\n" + soFieldNameOnLine + ": (integer)\nwhere (integer) is the tag id of the tag pointed to"; PARSE_PANIC( soErrorMessage ); } // find the tag--no, can't do this because the tag may not // have been read yet. Do it after reading the ace file and all // PHD files in dealWithTagPointers // tag* pFoundTag = ConsEd::pGetAssembly()->pFindTagWithThisID( lTagID ); // if ( !pFoundTag ) { // RWCString soErrorMessage = soFieldNameOnLine + // " is specified in the file " + pCP->filFileOfTagTypes_ + // " to be a pointer field to a tag but there is no tag with ID " + // soTagID; // PARSE_PANIC( soErrorMessage ); // } // if ( pUserDefinedTagFieldType->soPointerToWhichTagType_ != // pFoundTag->soType_ ) { // RWCString soErrorMessage = soFieldNameOnLine + // " is specified in the file " + pCP->filFileOfTagTypes_ + // " to be a pointer field to a tag of type " + // pUserDefinedTagFieldType->soPointerToWhichTagType_ + // " but tag with ID " + soTagID + // " has type " + pFoundTag->soType_; // PARSE_PANIC( soErrorMessage ); // } ((userDefinedPointerTagField*)pUserDefinedTagField)->lID_ = lTagID; // ((userDefinedPointerTagField*)pUserDefinedTagField)->pTag_ = pFoundTag; } else assert( false ); pUserDefinedTagField->pUserDefinedTagFieldType_ = pUserDefinedTagFieldType; }