2.8 File Listings

The code shown in listings 1-3 is available on your distribution disks as PERSON.H, PERSON.CPP, and DMTEST.CPP.

Listing 1

// person.h : Defines the class interfaces for CPerson, CPersonList.

//

// This is a part of the Microsoft Foundation Classes C++ library.

// Copyright (C) 1991 Microsoft Corporation

// All rights reserved.

//

// This source code is only intended as a supplement to the

// Microsoft Foundation Classes Reference and Microsoft

// QuickHelp documentation provided with the library.

// See these sources for detailed information regarding the

// Microsoft Foundation Classes product.

#ifndef __PERSON_H__

#define __PERSON_H__

#ifdef _DOS

#include <afx.h>

#else

#include <afxwin.h>

#endif

#include <afxcoll.h>

/////////////////////////////////////////////////////////////////////////////

// class CPerson:

// Represents one person in the phone database. This class is derived from

// CObject (mostly to get access to the serialization protocol).

class CPerson : public CObject

{

DECLARE_SERIAL( CPerson );

public:

//Construction

// For serializable classes, declare a constructor with no arguments.

CPerson()

{ m_modTime = CTime::GetCurrentTime(); }

CPerson( const CPerson& a );

// For our convenience, also declare a constructor with arguments.

CPerson( const char* pszLastName,

const char* pszFirstName,

const char* pszPhoneNum );

//Attributes

// Member functions to modify the protected member variables.

void SetLastName( const char* pszName )

{ ASSERT_VALID( this );

ASSERT( pszName != NULL);

m_LastName = pszName;

m_modTime = CTime::GetCurrentTime(); }

const CString& GetLastName() const

{ ASSERT_VALID( this );

return m_LastName; }

void SetFirstName( const char* pszName )

{ ASSERT_VALID( this );

ASSERT( pszName != NULL );

m_FirstName = pszName;

m_modTime = CTime::GetCurrentTime(); }

const CString& GetFirstName() const

{ ASSERT_VALID( this );

return m_FirstName; }

void SetPhoneNumber( const char* pszNumber )

{ ASSERT_VALID( this );

ASSERT( pszNumber != NULL );

m_PhoneNumber = pszNumber;

m_modTime = CTime::GetCurrentTime(); }

const CString& GetPhoneNumber() const

{ ASSERT_VALID( this );

return m_PhoneNumber; }

const CTime GetModTime() const

{ ASSERT_VALID( this );

return m_modTime; }

//Operations

CPerson& operator=( const CPerson& b );

//Implementation

protected:

// Member variables that hold data for person

CString m_LastName;

CString m_FirstName;

CString m_PhoneNumber;

CTime m_modTime;

public:

// Override the Serialize function

virtual void Serialize( CArchive& archive );

#ifdef _DEBUG

// Override Dump for debugging support

virtual void Dump( CDumpContext& dc ) const;

virtual void AssertValid() const;

#endif

};

/////////////////////////////////////////////////////////////////////////////

// class CPersonList:

// This represents a list of all persons in a phone database. This class is

// derived from CObList, a list of pointers to CObject-type objects.

class CPersonList : public CObList

{

DECLARE_SERIAL( CPersonList )

public:

//Construction

CPersonList()

{ m_bIsDirty = FALSE; }

// Add new functions

CPersonList* FindPerson( const char * szTarget );

// SetDirty/GetDirty

// Mark the person list as "dirty" (meaning "modified"). This flag can be

// checked later to see if the database needs to be saved.

//

void SetDirty( BOOL bDirty )

{ ASSERT_VALID( this );

m_bIsDirty = bDirty; }

BOOL GetDirty()

{ ASSERT_VALID( this );

return m_bIsDirty; }

// Delete All will delete the Person objects as well as the pointers.

void DeleteAll();

protected:

BOOL m_bIsDirty;

};

/////////////////////////////////////////////////////////////////////////////

#endif // __PERSON_H__

Listing 2

// person.cpp : Defines the class behaviors for CPerson, CPersonList.

//

// This is a part of the Microsoft Foundation Classes C++ library.

// Copyright (C) 1991 Microsoft Corporation

// All rights reserved.

//

// This source code is only intended as a supplement to the

// Microsoft Foundation Classes Reference and Microsoft

// QuickHelp documentation provided with the library.

// See these sources for detailed information regarding the

// Microsoft Foundation Classes product.

#include "person.h"

#include <string.h>

#ifdef _DEBUG

#undef THIS_FILE

static char BASED_CODE THIS_FILE[] = __FILE__;

#endif

////////////////////////////////////////////

//

// Call 'IMPLEMENT_SERIAL' macro for all the

// classes declared in person.h

IMPLEMENT_SERIAL( CPerson, CObject, 0 )

IMPLEMENT_SERIAL( CPersonList, CObList, 0 )

//////////////////////////////////////////////

// Define member functions for classes

// declared in person.h

//

//////////////////////////////////////////////

// CPerson::CPerson

// Copy Constructor for CPerson class

//

CPerson::CPerson( const CPerson& a )

{

m_LastName = a.m_LastName;

m_FirstName = a.m_FirstName;

m_PhoneNumber = a.m_PhoneNumber;

m_modTime = a.m_modTime;

}

//////////////////////////////////////////////

// CPerson::CPerson

// Memberwise Constructor for CPerson class

//

CPerson::CPerson( const char* pszLastName,

const char* pszFirstName,

const char* pszPhoneNum )

{

ASSERT_VALID( this );

m_LastName = pszLastName;

m_FirstName = pszFirstName;

m_PhoneNumber = pszPhoneNum;

m_modTime = CTime::GetCurrentTime();

}

//////////////////////////////////////////////

// CPerson::operator=

// Overloaded operator= to perform assignments.

//

CPerson& CPerson::operator=( const CPerson& b )

{

ASSERT_VALID( this );

ASSERT_VALID( &b );

m_LastName = b.m_LastName;

m_FirstName = b.m_FirstName;

m_PhoneNumber = b.m_PhoneNumber;

m_modTime = b.m_modTime;

return *this;

}

///////////////////////////////////////////////

// CPerson::Dump

// Write the contents of the object to a

// diagnostic context

//

// The overloaded '<<' operator does all the hard work

//

#ifdef _DEBUG

void CPerson::Dump( CDumpContext& dc ) const

{

ASSERT_VALID( this );

// Call base class function first

CObject::Dump( dc );

// Now dump data for this class

dc << "\n"

<< "Last Name: " << m_LastName << "\n"

<< "First Name: " << m_FirstName << "\n"

<< "Phone #: " << m_PhoneNumber << "\n"

<< "Modification date: " << m_modTime << "\n";

}

void CPerson::AssertValid() const

{

CObject::AssertValid();

}

#endif

/////////////////////////////////////////////

// CPerson::Serialize

// Read or write the contents of the object

// to an archive

//

void CPerson::Serialize( CArchive& archive )

{

ASSERT_VALID( this );

// Call base class function first

CObject::Serialize( archive );

// Now dump data for this class

if ( archive.IsStoring() )

{

archive << m_LastName << m_FirstName << m_PhoneNumber

<< m_modTime;

}

else

{

archive >> m_LastName >> m_FirstName >> m_PhoneNumber

>> m_modTime;

}

}

//////////////////////////////////////////////////////////////////////////////

// CPersonList

// We inherit most of the functionality from CObList. These are only

// functions that we added to form our own list type.

//

//////////////////////////////////////////////

// CPersonList::FindPerson

//

CPersonList* CPersonList::FindPerson( const char * szTarget )

{

ASSERT_VALID( this );

CPersonList* pNewList = new CPersonList;

CPerson* pNext = NULL;

// Start at front of list

POSITION pos = GetHeadPosition();

// Iterate over whole list

while( pos != NULL )

{

// Get next element (note cast)

pNext = (CPerson*)GetNext(pos);

// Add current element to new list if it matches

if ( _strnicmp( pNext -> GetLastName(), szTarget, strlen( szTarget ) )

== 0 )

pNewList -> AddTail(pNext);

}

if ( pNewList -> IsEmpty() )

{

delete pNewList;

pNewList = NULL;

}

return pNewList;

}

//////////////////////////////////////////

// CPersonList::DeleteAll

// This will delete the objects in the list as the pointers.

//

void CPersonList::DeleteAll()

{

ASSERT_VALID( this );

POSITION pos = GetHeadPosition();

while( pos != NULL )

{

delete GetNext(pos);

}

RemoveAll();

}

Listing 3

// dmtest.cpp : A program to test the CPerson and CPersonList classes.

//

// This is a part of the Microsoft Foundation Classes C++ library.

// Copyright (C) 1991 Microsoft Corporation

// All rights reserved.

//

// This source code is only intended as a supplement to the

// Microsoft Foundation Classes Reference and Microsoft

// QuickHelp documentation provided with the library.

// See these sources for detailed information regarding the

// Microsoft Foundation Classes product.

#include "person.h"

// Function prototypes.

CPersonList* MakeDataBase();

CFile* OpenForReading( const CString& rFileName );

CFile* OpenForWriting( const CString& rFileName );

CPersonList* ReadDataBase( CFile* pFile );

BOOL WriteDataBase( CFile* pFile, CPersonList* pDataBase );

void TestFindPerson( CPersonList* pDataBase );

void ListDataBase( CPersonList* db );

/////////////////////////////////////////////////////////////////////////////

void main()

{

const char szFileName[] = "tutorial.dat";

#ifdef _DEBUG

// Prepare for display of search results

const int nDumpChildren = 1;

afxDump.SetDepth( nDumpChildren );

#endif

printf( "Create a person list and fill it with persons\n" );

CPersonList* pDataBase = MakeDataBase();

printf( "Serialize the person list\n" );

CFile* pFile; // Declare a file object

TRY

{

// Could throw a file exception if can't open file

pFile = OpenForWriting( szFileName );

// Could throw an archive exception if can't create

WriteDataBase( pFile, pDataBase );

}

CATCH( CFileException, theException )

{

printf( "Unable to open file for writing\n" );

exit( -1 );

}

AND_CATCH( CArchiveException, theException )

{

printf( "Unable to save the database\n" );

pFile -> Close(); // Close up

delete pFile;

exit( -1 );

}

END_CATCH

// No exceptions, so close up

pFile -> Close();

delete pFile;

ListDataBase( pDataBase );

printf( "Delete the list and all its elements\n" );

pDataBase -> DeleteAll();

ListDataBase( pDataBase );

delete pDataBase;

printf( "Deserialize the data from disk into a new list\n" );

CPersonList* pDataBase2; // Create a new, empty list

TRY

{

// Could throw a file exception if can't open file

pFile = OpenForReading( szFileName );

// Could throw an archive exception if can't create

pDataBase2 = ReadDataBase( pFile );

}

CATCH( CFileException, theException )

{

printf( "Unable to open file for reading database\n" );

exit( -1 );

}

AND_CATCH( CArchiveException, theException )

{

printf( "Unable to read the database\n" );

pFile -> Close(); // Close up before exiting

delete pFile;

exit( -1 );

}

END_CATCH

// No exceptions, so close up

pFile -> Close();

delete pFile;

ListDataBase( pDataBase2 );

printf( "Test the FindPerson function\n" );

if ( pDataBase2 != NULL )

TestFindPerson( pDataBase2 );

printf( "Delete the list and all its elements\n" );

pDataBase2 -> DeleteAll();

delete pDataBase2;

TRACE( "End of program\n" );

}

// MakeDataBase - Create a database and add some persons

//

CPersonList* MakeDataBase()

{

TRACE( " Make a new person list on the heap\n" );

CPersonList* pDataBase = new CPersonList;

TRACE( " Add several new persons to the list\n" );

CPerson* pNewPerson1 = new CPerson( "Smith", "Mary", "435-8159" );

pDataBase -> AddHead( pNewPerson1 );

CPerson* pNewPerson2 = new CPerson( "Smith", "Al", "435-4505" );

pDataBase -> AddHead( pNewPerson2 );

CPerson* pNewPerson3 = new CPerson( "Jones", "Steve", "344-9865" );

pDataBase -> AddHead( pNewPerson3 );

CPerson* pNewPerson4 = new CPerson( "Hart", "Mary", "287-0987" );

pDataBase -> AddHead( pNewPerson4 );

CPerson* pNewPerson5 = new CPerson( "Meyers", "Brian", "236-1234" );

pDataBase -> AddHead( pNewPerson5 );

TRACE( " Return the completed database to main\n" );

return pDataBase;

}

// OpenForReading - open a file for reading

//

CFile* OpenForReading( const CString& rFileName )

{

CFile* pFile = new CFile;

CFileException* theException = new CFileException;

if ( !pFile -> Open( rFileName, CFile::modeRead, theException ) )

{

delete pFile;

TRACE( " Threw file exception in OpenForReading\n" );

THROW( theException );

}

delete theException;

// Exit here if no exceptions

return pFile;

}

// OpenForWriting - open a file for writing

//

CFile* OpenForWriting( const CString& rFileName )

{

CFile* pFile = new CFile;

CFileStatus status;

UINT nAccess = CFile::modeWrite;

// GetStatus will return TRUE if file exists,

// or FALSE if it doesn't exist

if ( !CFile::GetStatus( rFileName, status ) )

nAccess |= CFile::modeCreate;

CFileException* theException = new CFileException;

if ( !pFile -> Open( rFileName, nAccess, theException ) )

{

delete pFile;

TRACE( " Threw a file exception in OpenForWriting\n" );

THROW( theException );

}

delete theException;

// Exit here if no errors or exceptions

TRACE( " Opened file for writing OK\n" );

return pFile;

}

// ReadDataBase - read data into a person list

//

CPersonList* ReadDataBase( CFile* pFile )

{

CPersonList* pNewDataBase = NULL;

// Create an archive from pFile for reading

CArchive archive( pFile, CArchive::load );

TRY

{

// and deserialize the new data base from the archive

archive > pNewDataBase;

}

CATCH( CArchiveException, theException )

{

TRACE( " Caught an archive exception in ReadDataBase\n" );

#ifdef _DEBUG

theException -> Dump( afxDump );

#endif

archive.Close();

// If we got part of the database then delete it so we don't

// have any Memory leaks

if ( pNewDataBase != NULL )

{

pNewDataBase -> DeleteAll();

delete pNewDataBase;

}

THROW_LAST();

}

END_CATCH

// Exit here if no errors or exceptions

archive.Close();

return pNewDataBase;

}

// WriteDataBase - write data from a person list to disk

//

BOOL WriteDataBase( CFile* pFile, CPersonList* pDataBase )

{

// Create an archive from pFile for writing

CArchive archive( pFile, CArchive::store );

TRY

{

// and serialize the data base to the archive

archive < pDataBase;

}

CATCH( CArchiveException, theException )

{

TRACE( " Caught an archive exception in WriteDataBase\n" );

#ifdef _DEBUG

theException -> Dump( afxDump );

#endif

archive.Close();

THROW_LAST();

}

END_CATCH

// Exit here if no errors or exceptions

archive.Close();

return TRUE;

}

// TestFindPerson - test CPersonList::FindPerson

//

void TestFindPerson( CPersonList* pDataBase )

{

printf( " Looking for the name Banipuli\n" );

CPersonList* pFound = pDataBase -> FindPerson( "Banipuli" );

if ( pFound -> IsEmpty() )

{

printf( " No matching persons\n" );

}

else

{

printf( " Found matching persons\n" );

#ifdef _DEBUG

pFound -> Dump( afxDump );

#endif

}

delete pFound;

printf( " Looking for the name Smith\n" );

pFound = pDataBase -> FindPerson( "Smith" );

if ( pFound -> IsEmpty() )

{

printf( " No matching persons\n" );

}

else

{

printf( " Found matching persons\n" );

#ifdef _DEBUG

pFound -> Dump( afxDump );

#endif

}

// Don't DeleteAll the found list since it

// shares CPerson objects with dataBase

delete pFound; // Deletes only the list object

}

void ListDataBase( CPersonList* db )

{

CPerson* pCurrent;

POSITION pos;

if ( db -> GetCount() == 0 )

printf( " List is Empty\n" );

else

{

printf( " List contains:\n" );

pos = db -> GetHeadPosition();

while ( pos != NULL )

{

pCurrent = (CPerson*)db -> GetNext( pos );

printf( "\t%s, %s\t%s\n", (const char*)pCurrent -> GetLastName(),

(const char*)pCurrent -> GetFirstName(),

(const char*)pCurrent -> GetPhoneNumber() );

}

}

}