/***************************************************************************** # 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 #include #include "listOfLibraries.h" #include "mbt_exception.h" #include "library.h" #include "consedParameters.h" #include "fileDefines.h" #include "rwctokenizer.h" #include "bIsNumericMaybeWithWhitespace.h" #include "bIsNumericDouble.h" #include "assert.h" static int nLine; const size_t nMaxLineSize = 1000; static RWCString soLine( (size_t) nMaxLineSize ); static FILE* pLibrariesInfoFile; #define PARSE_PANIC( message ) \ { ostrstream ost; \ ost << "error in library file " << pCP->filPrimersLibrariesInfoFile_ << \ " at line " << \ nLine << \ ": \n" << \ soLine << endl << \ message << endl << \ "Error detected from source file " << \ __FILE__ << " at " << __LINE__ << endl << ends; \ InputDataError ide(ost.str()); \ throw ide; } #define FGETS_OR_PARSE_PANIC( szErrorMessage ) \ if ( fgets( soLine.sz_, nMaxLineSize, pLibrariesInfoFile ) == NULL ) \ PARSE_PANIC( szErrorMessage ); \ ++nLine; \ soLine.nCurrentLength_ = strlen( soLine.sz_ ); static int nCompareLibraries( const library** ppLib1, const library** ppLib2 ) { if ( (*ppLib1)->soName_ < (*ppLib2)->soName_ ) return( -1 ); else if ( (*ppLib1)->soName_ > (*ppLib2)->soName_ ) return( 1 ); else return( 0 ); } void listOfLibraries :: sortLibrariesByName() { void* pArray = (void*) aLibraries_.data(); size_t nNumberOfElementsInArray = aLibraries_.length(); size_t nSizeOfAnElement = sizeof( library* ); qsort( pArray, nNumberOfElementsInArray, nSizeOfAnElement, ( (int(*) ( const void*, const void* )) nCompareLibraries ) ); if ( ! bAreLibrariesSortedByName() ) { PANIC_OST( ost ) << "listOfLibraries :: sortLibrariesByName() didn't work" << ends; throw ProgramLogicError( ost.str() ); } } bool listOfLibraries :: bAreLibrariesSortedByName() { int nNumberOfEntries = aLibraries_.entries(); bool bSorted = true; if ( nNumberOfEntries >= 2 ) { for( int nElement = 0; nElement <= nNumberOfEntries - 2; ++nElement ) { if ( ( aLibraries_.operator[]( nElement + 1 ))->soName_ < ( aLibraries_.operator[]( nElement ))->soName_ ) { bSorted = false; cerr << "Elements " << nElement << " with value " << ( aLibraries_.operator[]( nElement ))->soName_ << " and " << nElement + 1 << " with value " << ( aLibraries_.operator[]( nElement + 1 ))->soName_ << " are out of order " << endl; } } } return( bSorted ); } void listOfLibraries :: parseLibraryFile() { // somewhere need to create the default library. Doing this in // Assembly :: assignLibrariesToSubcloneTTemplates() pLibrariesInfoFile = fopen( pCP->filPrimersLibrariesInfoFile_.data(), "r" ); if ( !pLibrariesInfoFile ) { if ( pCP->nWhatIsRunning_ != nGraphicalConsedIsRunning ) { if ( errno == 2 ) { fprintf( pFILE, "There is no file %s\n", pCP->filPrimersLibrariesInfoFile_.data() ); fprintf( pFILE, "--that's ok\n" ); } else { fprintf( pFILE, "Could not open libraries info file %s\n", pCP->filPrimersLibrariesInfoFile_.data() ); fprintf( pFILE, "error = %d which means %s\n", errno, strerror( errno ) ); fprintf( pFILE, "So Autofinish will assume that all templates came \nfrom the same library, and thus they all have \napproximately the same insert size\n" ); } } return; } // LIB{ // name: ab08 // avgInsertSize: 1500 // maxInsertSize: 3000 // stranded: double // cost: 600.0 // } // // LIB{ // name: ab09 // avgInsertSize: 1500 // maxInsertSize: 3000 // stranded: double // cost: 600.0 // } // // LIB{ // name: ab10 // avgInsertSize: 3000 // maxInsertSize: 5000 // stranded: single // cost: 1200.0 // } // // look for LIB{ or end-of-file bool bEndOfFile = false; do { if ( fgets( soLine.sz_, nMaxLineSize, pLibrariesInfoFile ) == NULL ) bEndOfFile = true; else { ++nLine; soLine.nCurrentLength_ = strlen( soLine.sz_ ); } soLine.stripTrailingWhitespaceFast(); if ( soLine == "LIB{" ) parseLibraryBlock(); } while( !bEndOfFile ); fclose( pLibrariesInfoFile ); // sort the libraries based on the library name sortLibrariesByName(); } void listOfLibraries :: parseLibraryBlock() { library* pLib = new library(); bool bNameFound = false; bool bStrandedFound = false; bool bAvgInsertSizeFound = false; bool bMaxInsertSizeFound = false; bool bCostFound = false; bool bEndOfLibBlock = false; do { FGETS_OR_PARSE_PANIC( "while expecting \"}\" to close LIB{ block" ); soLine.stripTrailingWhitespaceFast(); if ( soLine == "}" ) bEndOfLibBlock = true; else { RWCTokenizer tok( soLine ); RWCString soLabel = tok(); RWCString soValue = tok(); if ( soLabel == "name:" ) { pLib->soName_ = soValue; bNameFound = true; } else if ( soLabel == "avgInsertSize:" ) { if ( !bIsNumericMaybeWithWhitespace( soValue, pLib->nDefaultInsertSize_ ) ) { PARSE_PANIC( "could not convert insert size--is this a number?" ); } bAvgInsertSizeFound = true; } else if ( soLabel == "maxInsertSize:" ) { if ( !bIsNumericMaybeWithWhitespace( soValue, pLib->nMaxInsertSize_ ) ) { PARSE_PANIC( "could not convert max insert size--is this a number?" ); } pLib->nMaxInsertSizeFromFile_ = pLib->nMaxInsertSize_; if ( pLib->nMaxInsertSize_ > pCP->nPrimersMaxInsertSizeOfASubclone_ ) { RWCString soError = RWCString( "consed.primersMaxInsertSizeOfASubclone is set at " ) + pCP->nPrimersMaxInsertSizeOfASubclone_ + " but library " + pLib->soName_ + " has a maximum insert size of " + pLib->nMaxInsertSize_ + "\nThese are inconsistent. I will increase consed.primersMaxInsertSizeOfASubclone"; cerr << soError << endl; pCP->nPrimersMaxInsertSizeOfASubclone_ = pLib->nMaxInsertSize_; } bMaxInsertSizeFound = true; } else if ( soLabel == "stranded:" ) { if ( soValue == "single" ) pLib->bSingleNotDoubleStranded_ = true; else if ( soValue == "double" ) pLib->bSingleNotDoubleStranded_ = false; else { PARSE_PANIC( "stranded: must be followed by \"single\" or \"double\"" ); } bStrandedFound = true; } else if ( soLabel == "cost:" ) { if ( !bIsNumericDouble( soValue, pLib->dCostToMakeMinilibrary_ ) ) { PARSE_PANIC( "could not convert cost--is this a number?" ); } bCostFound = true; } } } while( ! bEndOfLibBlock ); if ( !bNameFound ) PARSE_PANIC( "LIB block just read has no name: (name)" ); if ( pLib->soName_.isNull() ) PARSE_PANIC( "In LIB block just read, name: line must be of form name: (name)" ); if ( !bCostFound ) pLib->dCostToMakeMinilibrary_ = pCP->dAutoFinishCostOfMinilibrary_; if ( !bAvgInsertSizeFound ) { PARSE_PANIC( "LIB block just read has no avgInsertSize: (size)" ); } if ( !bMaxInsertSizeFound ) { PARSE_PANIC( "LIB block just read has no maxInsertSize: (size)" ); } if ( !bStrandedFound ) { PARSE_PANIC( "LIB block just read has no stranded: double or stranded: single" ); } if ( !bCostFound ) { PARSE_PANIC( "LIB block just read has no cost: 600.0" ); } aLibraries_.insert( pLib ); } static int nCompareKeyToLibrary(const RWCString* pLibraryName, const library** ppLib ) { if ( (*pLibraryName) < (*ppLib)->soName_ ) return( -1 ); else if ( (*pLibraryName) > (*ppLib)->soName_ ) return( 1 ); else return( 0 ); } library* listOfLibraries :: pFindLibraryByName( const RWCString& soLibraryName ) { // fix for solaris-intel if ( aLibraries_.length() == 0 ) return NULL; library** ppLib = (library**) bsearch( &soLibraryName, aLibraries_.data(), aLibraries_.length(), sizeof( library* ), (int(*) ( const void*, const void* )) nCompareKeyToLibrary ); if ( ppLib != NULL ) { assert( soLibraryName == (*ppLib)->soName_ ); } if ( ppLib == NULL ) return( NULL ); else return( *ppLib ); }