// TSList.cpp: implementation of the base class: TSList, // inherited classes: TSRecordList, TSTreeList and TSFieldList, and // associated class: TSPosition. // ///////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #include "TSField.h" #include "TSList.h" #include "TSRecord.h" #include "TSServer.h" #pragma warning( disable: 4710 ) // inlined function not inlined /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * TSList base class methods * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ TSList::TSList() : first ( NULL ), last ( NULL ), length ( 0 ) { } TSList::TSList( const TSList& sourceList ) : first ( NULL ), last ( NULL ), length ( 0 ) { this->Copy( &sourceList ); } TSList::~TSList() { } TSList& TSList::operator=( const TSList& sourceList ) { this->Copy( &sourceList ); return *this; } TSPosition* TSList::GetFirst() const { return first; } TSPosition* TSList::GetLast() const { return last; } TSPosition* TSList::GetNext( TSPosition* pos ) const { if ( pos == NULL ) { return NULL; } return pos->next; } TSPosition* TSList::GetPrev( TSPosition* pos ) const { if ( pos == NULL ) { return NULL; } return pos->prev; } TSObject* TSList::GetAt( TSPosition* pos ) const { return pos->object; } int TSList::AddHead( TSObject* object ) { first = new TSPosition( first, NULL, object ); if ( first == NULL ) { TSSetLastErrorMessage( "Unable to allocate memory for TSPosition in TSList::AddHead()." ); TSSetLastError( TS_MEMORY_ERROR ); return TSGetLastError(); } if ( last == NULL ) { last = first; } else { first->next->prev = first; } length++; return TS_OK; } int TSList::AddTail( TSObject* object ) { last = new TSPosition( NULL, last, object ); if ( last == NULL ) { TSSetLastErrorMessage( "Unable to allocate memory for TSPosition in TSList::AddTail()." ); TSSetLastError( TS_MEMORY_ERROR ); return TSGetLastError(); } if ( first == NULL ) { first = last; } else { last->prev->next = last; } length++; return TS_OK; } int TSList::InsertAfter( TSPosition* pos, TSObject* object ) { if ( pos == NULL ) { TSSetLastError( TS_MEMORY_ERROR ); return TSGetLastError(); } TSPosition* newPos; newPos = new TSPosition( pos->next, pos, object ); if ( newPos == NULL ) { TSSetLastErrorMessage( "Unable to allocate memory for TSPosition in TSList::InsertAfter()." ); TSSetLastError( TS_MEMORY_ERROR ); return TSGetLastError(); } if ( last == pos ) { last = newPos; } pos->next->prev = newPos; pos->next = newPos; length ++; return TS_OK; } int TSList::InsertBefore( TSPosition* pos, TSObject* object ) { if ( pos == NULL ) { TSSetLastError( TS_MEMORY_ERROR ); return TSGetLastError(); } TSPosition* newPos = new TSPosition( pos, pos->prev, object ); if ( newPos == NULL ) { TSSetLastErrorMessage( "Unable to allocate memory for TSPosition in TSList::InsertBefore()." ); TSSetLastError( TS_MEMORY_ERROR ); return TSGetLastError(); } if ( first == pos ) { first = newPos; } pos->prev->next = newPos; pos->prev = newPos; length ++; return TS_OK; } // Duplicate the contents of this list onto newList. int TSList::Duplicate( TSList* newList, int type ) const { newList->EmptyAndDestroyList(); TSPosition* pos; TSObject* obj; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { if ( (type == 0) || (pos->object->fieldType == 0) || (pos->object->fieldType == type) ) { obj = pos->object->Duplicate(); if ( obj == NULL ) { TSSetLastError( TS_MEMORY_ERROR ); return TSGetLastError(); } newList->AddTail( obj ); } } return TS_OK; } // Copies the contents of sourceList list onto this list. int TSList::Copy( const TSList* sourceList ) { EmptyAndDestroyList(); TSPosition* pos; for ( pos = sourceList->GetFirst(); pos != NULL; pos = sourceList->GetNext( pos )) { AddTail( pos->object ); } return TS_OK; } TSString TSList::StringDump( int recursive, TSString indentation ) { TSPosition* pos; TSString s = indentation + "LIST:\n"; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { s += pos->object->StringDump( recursive, indentation + " " ); } return s; } int TSList::SocketString( TSString& str ) { TSPosition* pos; TSString tmp; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { pos->object->SocketString( tmp ); str += tmp; } str += "\r\n"; return TS_OK; } TSPosition* TSList::Get( int index ) const { TSPosition* pos; int cntr = 0; for ( pos = GetFirst(); pos != NULL && cntr != index; pos = GetNext( pos )) { cntr ++; } return pos; } TSObject* TSList::RemoveObject( TSObject* pObject ) { // First find the position, then call the other remove object; for ( TSPosition *pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { if ( pos->object == pObject ) return RemoveObject( pos ); } return NULL; } TSObject* TSList::RemoveObject( int index ) { return RemoveObject( Get( index )); } TSObject* TSList::RemoveObject( TSPosition* pos ) { if ( pos == NULL ) { return NULL; } if ( pos->next ) { pos->next->prev = pos->prev; } else { last = pos->prev; } if ( pos->prev ) { pos->prev->next = pos->next; } else { first = pos->next; } TSObject* obj = pos->object; delete pos; length--; return obj; } void TSList::EmptyList() { TSObject* obj; while (( obj = RemoveObject( 0 )) != NULL ); } void TSList::EmptyAndDestroyList() { TSObject* obj; while (( obj = RemoveObject( 0 )) != NULL ) { delete obj; } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Inherited class TSRecordList methods * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ TSRecordList::TSRecordList() : TSList(), m_bIsFieldList( FALSE ) { } TSRecordList::~TSRecordList() { } int TSRecordList::Receive( TSServer* server, TSSocket* socket ) { TSRecord* rec; int fieldType; int tableId; char ch; int nReturn = socket->ReceiveInt( &tableId ); if ( nReturn != TS_OK ) { // TSErrorCode is set in ReceiveInt() return TSGetLastError(); } // Create one master record which reads the schema information and // then duplicate it for each record in the list. TSRecord master( tableId, server ); while ( socket->ReceiveInt( &fieldType ) == TS_OK ) { master.fieldType = fieldType; rec = static_cast(master.Duplicate() ); nReturn = rec->Receive( socket ); if ( nReturn != TS_OK ) { delete rec; // TSErrorCode is set in Receive() return TSGetLastError(); } // If this is a fields list of records, eliminate dups. This is very // important since duplicate field records may make the CopyFrom and // CopyTo functions work incorrectly. if ( m_bIsFieldList ) { TSRecord* pTempRec = FindRecordByDbName( rec->GetString( "dbname" ), rec->tableId, rec->fieldType, rec->sqlDataType ); if ( pTempRec ) { delete RemoveObject( pTempRec ); } } nReturn = AddTail( rec ); if ( nReturn != TS_OK ) { delete rec; // TSErrorCode is set in AddTail() return TSGetLastError(); } } // There's always a \r\n at the end of the list, but usually the \r has // already been read so read up till the next \n. while (( ch = socket->ReadChar()) != 0 ) if ( ch == '\n' ) { break; } return TS_OK; } int TSRecordList::SocketString( TSString& str ) { TSPosition* pos; TSRecord* rec; TSString s; str = ""; // All of the records in the list had better have the same table id so // we'll get it from the first record. pos = GetFirst(); if ( pos != NULL ) { TSEncodeInt( GetAt( pos )->tableId, str ); while ( pos != NULL ) { rec = GetAt( pos ); s = ""; TSEncodeInt( rec->fieldType, s ); str += s; rec->SocketString( s ); str += s; pos = GetNext( pos ); } } else { // If there's nothing in the list we still need to in a tableId for a // place holder. TSEncodeInt( 0,str ); } str += "\r\n"; return TS_OK; } // Find a record with the same structure rather than the same data. TSRecord* TSRecordList::FindRecord( const char* fieldName, int nTableId, int nFieldType, int nSqlDataType ) { if ( !fieldName ) { return NULL; } TSRecord* rec; TSPosition* pos; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { rec = GetAt( pos ); if ( rec ) { if (( rec->tableId == nTableId ) && ( rec->fieldType == nFieldType ) && ( rec->sqlDataType == nSqlDataType ) ) { const char* pcName = rec->GetString( "name" ); if ( pcName && ( strcmp( pcName, fieldName ) == 0 ) ) { return rec; } } } } return NULL; } // Find a record with the same structure rather than the same data. TSRecord* TSRecordList::FindRecordByDbName( const char* fieldDbName, // Needs to be the database name of the field int nTableId, int nFieldType, int nSqlDataType ) { if ( !fieldDbName ) { return NULL; } TSRecord* rec; TSPosition* pos; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { rec = GetAt( pos ); if ( rec ) { if (( rec->tableId == nTableId ) && ( rec->fieldType == nFieldType ) && ( rec->sqlDataType == nSqlDataType ) ) { const char* pcDbName = rec->GetString( "dbname" ); if ( pcDbName && ( strcmp( pcDbName, fieldDbName ) == 0 ) ) { return rec; } } } } return NULL; } TSRecord* TSRecordList::FindRecord( const char* fieldName, int searchValue ) { if ( !fieldName ) { return NULL; } TSRecord* rec; TSPosition* pos; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { rec = GetAt( pos ); if ( rec->GetInt( fieldName ) == searchValue ) { return rec; } } return NULL; } TSRecord* TSRecordList::FindRecord( const char* fieldName, double searchValue ) { if ( !fieldName ) { return NULL; } TSRecord* rec; TSPosition* pos; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { rec = GetAt( pos ); if ( rec->GetDouble( fieldName ) == searchValue ) { return rec; } } return NULL; } TSRecord* TSRecordList::FindRecord( const char* fieldName, const char* searchValue ) { if ( !fieldName || !searchValue ) { return NULL; } TSRecord* rec; TSPosition* pos; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { rec = GetAt( pos ); char* str = rec->GetString( fieldName ); if ( str ) { if ( strcmp( str, searchValue ) == 0 ) { return rec; } } } return NULL; } TSRecord* TSRecordList::FindRecord( int recId ) { TSRecord* rec; TSPosition* pos; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { rec = GetAt( pos ); if ( rec->GetInt( "id" ) == recId ) { return rec; } } return NULL; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Inherited class TSFieldList methods * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ TSString TSFieldList::DumpSchema( TSString indentation ) { TSPosition* pos; TSString s = indentation + "LIST:\n"; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { s += GetAt( pos )->DumpSchema( indentation + " " ); } return s; } TSField* TSFieldList::FindFieldByName( const char* fieldName, int fieldType ) { if ( !fieldName ) { return NULL; } TSPosition* pos; TSField* field; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { field = GetAt( pos ); #ifdef WIN32 if ( stricmp( field->fieldName, fieldName ) == 0 && ( field->fieldType == fieldType || fieldType == 0 || field->fieldType == 0 )) #else if ( strcasecmp( field->fieldName, fieldName ) == 0 && ( field->fieldType == fieldType || fieldType == 0 || field->fieldType == 0 )) #endif { return field; } } return NULL; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Inherited class TSTreeList methods * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ TSRecord* TSTreeList::FindRecord( int recId ) { TSRecord* rec; TSPosition* pos; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { rec = GetAt( pos ); if ( rec->GetInt( "id" ) == recId ) { return rec; } // Search sub tree TSTreeList* subList = rec->GetSubTreeList(); if ( subList != NULL ) { rec = subList->FindRecord( recId ); if ( rec != NULL ) { return rec; } } } return NULL; } TSRecord* TSTreeList::FindRecord( const char* fieldName, int searchValue ) { if ( !fieldName ) { return NULL; } TSRecord* rec; TSPosition* pos; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { rec = GetAt( pos ); if ( rec->GetInt( fieldName ) == searchValue ) { return rec; } // Search sub tree TSTreeList* subList = rec->GetSubTreeList(); if ( subList != NULL ) { rec = subList->FindRecord( fieldName, searchValue ); if ( rec != NULL ) { return rec; } } } return NULL; } TSRecord* TSTreeList::FindRecord( const char* fieldName, double searchValue ) { if ( !fieldName ) { return NULL; } TSRecord* rec; TSPosition* pos; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { rec = GetAt( pos ); if ( rec->GetDouble( fieldName ) == searchValue ) { return rec; } // Search sub tree TSTreeList* subList = rec->GetSubTreeList(); if ( subList != NULL ) { rec = subList->FindRecord( fieldName, searchValue ); if ( rec != NULL ) { return rec; } } } return NULL; } TSRecord* TSTreeList::FindRecord( const char* fieldName, const char* searchValue ) { if ( !fieldName || !searchValue ) { return NULL; } TSRecord* rec; TSPosition* pos; for ( pos = GetFirst(); pos != NULL; pos = GetNext( pos )) { rec = GetAt( pos ); char* str = rec->GetString( fieldName ); if ( strcmp( str, searchValue ) == 0 ) { return rec; } // Search sub tree TSTreeList* subList = rec->GetSubTreeList(); if ( subList != NULL ) { rec = subList->FindRecord( fieldName, searchValue ); if ( rec != NULL ) { return rec; } } } return NULL; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * TSPosition object methods. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ TSPosition::TSPosition() { next = prev = NULL; object = NULL; } TSPosition::TSPosition( TSPosition* nextPos, TSPosition* prevPos, TSObject* thisObj ) { next = nextPos; prev = prevPos; object = thisObj; }