And now a C++ STL list version of the top Clist program ...
/* employeeRec's_list.cpp */ /* this version: 2011-08-08 */
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <list>
#include <cstdlib> /* re. atoi */
#include <cctype> /* re. tolower */
using namespace std;
#define FILENAME "employeeRecords.txt"
#define MENU " 1. Enter a new record. \n" \
" 2. Retrieve a record by name (ignore case). \n" \
" 3. Retrieve a record by phone number. \n" \
" 4. Show all records. \n" \
" 5. Sort all records by name (ignore case). \n" \
" 6. Sort all records by phone number. \n" \
" 7. Chop exact duplicates from records (use case). \n" \
" 8. Edit/Delete a record. \n" \
" 9. Write new file of sorted unique records. \n" \
"10. Exit \n"
#define PROMPT "Enter a number in range 1 to 10 : "
struct Employee
{
string name;
string address;
string phone;
} ;
typedef list< Employee > myList;
typedef list< Employee >::iterator myIter;
typedef list< Employee >::const_iterator c_myIter;
int strcmpIgnoreCase( const string&, const string& );
int strcmpWithCase( const string&, const string& );
bool cmpIgnoreCase( const Employee&, const Employee& );
bool cmpWithCase( const Employee&, const Employee& );
bool cmpPhone( const Employee&, const Employee& );
bool operator == ( const Employee&, const Employee& ); // for unique ...
void show( const Employee& r )
{
char phFormated[] = "(###) ###-####";
char* p = phFormated;
for( int i = 0; *p ; ++p ) if( *p == '#' ) { *p = r.phone[i]; ++i; }
cout << left << setw(22) << r.name << " "
<< setw(30) << r.address << " " << phFormated << right << endl;
}
void showAll( const myList& lst )
{
size_t i = 0;
for( c_myIter p = lst.begin(); p != lst.end(); ++p )
{
cout << "<" << setfill('0') << setw(3) << ++i << "> " << setfill(' ');
show( *p );
if( i % 5 == 0 && i != lst.size() ) cout << endl;
}
cout << "\nEmployee records on file = " << lst.size() << endl << endl;
}
/* ignore case compare function ... */
int strcmpIgnoreCase( const string& a, const string& b )
{
size_t i, lenA = a.size(), lenB = b.size();
for( i = 0; i < lenA && i < lenB; ++i )
{
if( tolower(a[i]) != tolower(b[i]) ) break;
}
/* ok ... check the end conditions ... */
if( i < lenA )
{
if( i < lenB ) return tolower(a[i]) - tolower(b[i]);
//else ...
return 1; // i.e. b < a
}
// else // if reach here ... i == lenA
if( i < lenB ) return -1; // i.e. a < b
// else // if reach here ... i == lenA ...AND... i == lenB
return 0; // i.e. a == b
}
/* case compare function ... */
int strcmpWithCase( const string& a, const string& b )
{
size_t i, lenA = a.size(), lenB = b.size();
for( i = 0; i < lenA && i < lenB; ++i )
{
if( a[i] != b[i] ) break;
}
/* ok ... check the end conditions ... */
if( i < lenA )
{
if( i < lenB ) return a[i] - b[i];
//else ...
return 1; // i.e. b < a
}
// else // if reach here ... i == lenA
if( i < lenB ) return -1; // i.e. a < b
// else // if reach here ... i == lenA ...AND... i == lenB
return 0; // i.e. a == b
}
bool cmpIgnoreCase( const Employee& x, const Employee& y )
{
int compare1 = strcmpIgnoreCase( x.name, y.name ); /* first compare names */
if( compare1 == 0 ) /* if the same ... */
{
int compare2 = strcmpIgnoreCase( x.address, y.address ); /* then address */
if( compare2 == 0 ) /* if the same ... */
return x.phone < y.phone; /* then phone number ... */
/* else ...*/
return compare2 < 0; /* use addresses after all ... */
}
/* else ... */
return compare1 < 0; /* use names afer all ... since names were NOT the same */
}
bool cmpWithCase( const Employee& x, const Employee& y )
{
int compare1 = strcmpWithCase( x.name, y.name ); /* first compare names */
if( compare1 == 0 ) /* if the same ... */
{
int compare2 = strcmpWithCase( x.address, y.address ); /* then address */
if( compare2 == 0 ) /* if the same ... */
return x.phone < y.phone; /* then phone number ... */
/* else ...*/
return compare2 < 0; /* use addresses after all ... */
}
/* else ... */
return compare1 < 0; /* use names afer all ... since names were NOT the same */
}
bool cmpPhone( const Employee& x, const Employee& y )
{
int compare1 = strcmpWithCase( x.phone, y.phone ); /* first compare phones */
if( compare1 == 0 ) /* if the same ... */
{
int compare2 = strcmpWithCase( x.name, y.name ); /* then names */
if( compare2 == 0 ) /* if the same ... */
return x.address < y.address; /* then address ... */
/* else ...*/
return compare2 < 0; /* use names after all ... */
}
/* else ... */
return compare1 < 0; /* use phones afer all ... since were NOT the same */
}
bool operator ==( const Employee& x, const Employee& y )
{
if( x.name != y.name ) return false; /* first compare names */
if( x.address != y.address ) return false; /* then address */
if( x.phone != y.phone ) return false; /* then phone number ... */
//else ...
return true;
}
int getChoice( const string& );
int showMenuGetChoice( myList& );
void readFile( myList& );
bool isValidPhoneNum( const string& );
myIter getNameIgnoreCase( myList&, const string& );
myIter getNumber( myList&, const string& );
Employee enterEmployee();
void takeInRecAndFile( myList& );
void writeSortedUnique( myList& );
void editDel( myList& );
void edit( myList&, myIter& );
void del( myList&, myIter& );
int main() /* ********************* MAIN BEGINS ***************************** */
{
int choice;
myList ml;
readFile( ml ); /* passing ml by reference so object gets updated */
if( ml.size() == 0 )
cout << "File " << FILENAME
<< " will be created after data has been entered." << endl;
else
cout << "Now &(*ml.begin()) = " << hex << &(*ml.begin()) << " and "
<< "ml.size = " << dec << ml.size() << endl << endl;
do
{
showAll( ml ); /* passing ml by reference to avoid making another copy */
choice = showMenuGetChoice( ml ); /* passing address ... */
cout << endl;
}
while( choice != 10 ); /* i.e. exit on choice of 10 ... */
cout << "Now &(*ml.begin()) = 0x" << hex << &(*ml.begin()) << " and "
<< "ml.size = " << ml.size() << endl << endl;
/* if using windows ... can do this ... especially while debugging */
system( "notepad " FILENAME );
} /* **************************** MAIN ENDS ********************************* */
int getChoice( const string& text )
{
cout << text << flush;
int reply = tolower( cin.get() );
cin.sync();
return reply;
}
void readFile( myList& lst )
{
ifstream fin( FILENAME );
if( !fin )
{
cout << "File " << FILENAME << " NOT found ..." << endl;
}
else
{
Employee d;
while
(
getline( fin, d.name ) && getline( fin, d.address )
&& getline( fin, d.phone )
)
{
lst.push_back( d );
}
fin.close();
}
}
int showMenuGetChoice( myList& lst )
{
int num;
string tmp;
cout << MENU << flush;
while
(
cout << PROMPT
&& getline( cin, tmp )
&& ( (num = atoi(tmp.c_str())) < 1 || num > 10 )
)
{
cout << "Out of valid range 1..10 " << flush;
}
if( num == 1 ) takeInRecAndFile( lst );
else if( num == 2 )
{
cout << "Enter the name to find: " << flush;
getline(cin, tmp);
myIter it;
if( (it = getNameIgnoreCase( lst, tmp )) == lst.end() )
cout << tmp << " not found." << endl;
else
show( *it );
}
else if( num == 3 )
{
cout << "Enter the number to find: " << flush;
getline(cin, tmp);
myIter it;
if( (it = getNumber( lst, tmp )) == lst.end() )
cout << tmp << " not found." << endl;
else
show( *it );
}
//else if( num == 4 ) showAll( list );
else if( num == 5 ) lst.sort( cmpIgnoreCase );
else if( num == 6 ) lst.sort( cmpPhone );
else if( num == 7 ) { lst.sort( cmpWithCase ); lst.unique(); }
else if( num == 8 ) editDel ( lst );
else if( num == 9 ) writeSortedUnique( lst );
/* else is 10 ... so will exit ... */
return num;
}
/* validates that 10 char's are present and all are numeric ... */
bool isValidPhoneNum( const string& ph )
{
if( ph.size() != 10 ) return false;
for( int i = 0; i < 10; ++i )
if( ph[i] < '0' || ph[i] >'9' ) return false;
return true;
}
/* returns valid iterbif found ... otherwise, returns ml.end() if NOT found */
myIter getNameIgnoreCase( myList& ml, const string& nameStr )
{
for( myIter it = ml.begin(); it != ml.end(); ++it )
if( strcmpIgnoreCase(it->name, nameStr) == 0 ) return it;
return ml.end();
}
myIter getNumber( myList& ml, const string& numStr )
{
for( myIter it = ml.begin(); it != ml.end(); ++it )
if( strcmpWithCase(it->phone, numStr) == 0 ) return it;
return ml.end();
}
Employee enterEmployee()
{
Employee d;
cout << "Enter name: " << flush;
getline( cin, d.name );
cout << "Enter address: "<< flush;
getline( cin, d.address );
for( ; ; )
{
cout << "Enter telephone: " << flush;
getline( cin, d.phone );
if( isValidPhoneNum(d.phone) )
{
break;
}
/* else ... */
cout << "Only 10 digit number valid here ... " << flush;
}
return d;
}
void takeInRecAndFile( myList& lst )
{
ofstream fout( FILENAME, ios::app );
if( !fout )
{
cout << "Error: " << FILENAME << " not opened." << endl;
return;
}
Employee d = enterEmployee();
/* Now we have good data ... so file and add to vector if ok ? */
if( getChoice( "Ok ... (y/n) ? " ) == 'y' )
{
fout << d.name << '\n' << d.address << '\n' << d.phone << endl;
lst.push_back( d );
cout << "Information has been filed in file " << FILENAME << endl;
}
else
{
cout << "Aborted ..." << endl;
}
fout.close();
}
void writeSortedUnique( myList& lst )
{
ofstream fout( "SU" FILENAME ); /* compiler concat's the text's ... */
if( !fout )
{
cout << "Error: file SU" << FILENAME << " failed to open." << endl;
return;
}
/* ok ... file is open ... so write all rec's to file ..*/
/* first ... make sure sorted and unique */
lst.sort( cmpWithCase );
lst.unique();
int i = 0;
for( c_myIter it = lst.begin(); it != lst.end(); ++it )
{
fout << "<" << setfill('0') << setw(3) << ++i << "> "
<< setfill(' ') << left << setw(24) << it->name << " "
<< setw(32) << it->address << " "
<< it->phone << right << endl;
if( i % 5 == 0 ) fout << endl;
}
fout.close(); /* flushes buffer ... so all written to file now ... */
cout << i << " records filed in file SU" << FILENAME
<< ", list size " << lst.size() << endl << endl;
/* and if have Windows OS ... can do this ... */
system( "notepad SU" FILENAME ); /*compiler concat's text at compile time*/
}
void editDel( myList& lst )
{
myIter it;
string tmp;
for( ; ; )
{
int reply = getChoice( "Find by Name/Phone/Abort (n/p/a) ? " );
if( reply == 'n' )
{
cout << "Enter the name to find: " << flush;
getline( cin, tmp );
if( (it = getNameIgnoreCase( lst, tmp )) == lst.end() )
cout << tmp << " not found." << endl;
else
{
show( *it );
reply = getChoice( "Edit/Delete/Abort (e/d/a) ? " );
if( reply == 'e' ) edit( lst, it );
else if( reply == 'd' ) del( lst, it );
else if( reply == 'a' )
{
cout << "Ok, edit/delete aborted ..."<< endl;
break;
}
}
}
else if( reply == 'p' )
{
cout << "Enter the number to find: " << flush;
getline(cin, tmp);
if( (it = getNumber( lst, tmp )) == lst.end() )
cout << tmp << " not found." << endl;
else
{
show( *it );
reply = getChoice( "Edit/Delete/Abort (e/d/a) ? " );
if( reply == 'e' ) edit( lst, it );
else if( reply == 'd' ) del( lst, it );
else if( reply == 'a' )
{
cout << "Ok, edit/delete aborted ..." << flush;
break;
}
}
}
else if( reply == 'a' )
{
cout << "Ok, edit/delete aborted ..." << flush;
break;
}
else cout << "Only n/p/a are valid ... " << flush;
}
}
void edit( myList& lst, myIter& it )
{
Employee d = enterEmployee();
/* ok ... we have some new data ... */
if( getChoice( "Ok ... (y/n) ? " ) == 'y' )
{ /* then edit ... */
it->name =d.name;
it->address =d.address;
it->phone =d.phone;
return;
}
/* else ... */
cout << "Aborted ..." << endl;
}
void del( myList& lst, myIter& it )
{
for( ; ; )
{
int reply = getChoice( "Really delete/abort (d/a) ? " );
if( reply == 'a' )
{
cout << "Delete aborted ..." << flush;
return;
}
/* else ... */
if( reply == 'd' )
{
lst.erase( it );
return;
}
/* else ... */
cout << "Enter 'd' and WILL delete ... or 'a' to abort ..." << endl;
}
}