#include <cstdio>
#include <cstdlib>
#include <string>
#include <iostream>
using namespace std;
// Function Headers
void Create();
void Dump();
void Insert();
void Delete();
void Print();
int AddDigits(char * psSSN);
FILE * Find(char * key);
void Retrieve();
// Global Variables
int mnRecordLength = 46; // Length of each record 3(Delete Flag) + 10(SSN) + 21(Name) + 10(Salary) + 2(CRLF)
int mnHeaderSize = 6; // The size of our header record holding number of records in overflow
FILE *mioHashFile; // Internal file pointer for our IO commands
int mnOverlowRecords; // number of records in overflow
// Main program that presents a menu of options to the user and calls the various functions
int main()
{
char sOption;
cout << "Enter a Menu Selection - (C)reate, (I)nsert, (R)etrieve, X=Delete, (P)rint, (D)ump, (Q)uit" << endl;
cin >> sOption;
while (sOption != 'Q')
{
switch ( sOption )
{
case 'C':
Create();
break;
case 'I':
Insert();
break;
case 'D':
Dump();
break;
case 'X':
Delete();
break;
case 'P':
Print();
break;
case 'R':
Retrieve();
break;
default:
cout << "Invalid Menu Option Entered \n";
}
cout << "Enter a Menu Selection - (C)reate, (I)nsert, (R)etrieve, X=Delete, (P)rint, (D)ump, (Q)uit" << endl;
cin >> sOption;
}
return 0;
}
// This function opens the emp file for output which will remove all records already out there
// It then writes a header record that contains the overflow record number (0)
// and then writes 10 empty records into the file
void Create()
{
mioHashFile = fopen ("emp", "w");
//Write a Header Record that contains the number of the overflow records written (0)
fprintf (mioHashFile, "%4d\n", 0);
// Initialize emp file with fixed length dummy records.
// Assume there are 10 records in the file.
for (int nRecords = 0; nRecords < 10; nRecords++)
{
fprintf (mioHashFile, "%3d%10s%21s%10.2f\n", -1, "x", "x", 0.0);
}
fclose(mioHashFile);
cout << "create complete\n";
return;
}
// This function is used to insert a new record into out employee file.
// It first calculates the hash for the record and reads that record to determine
// if it has been used before. If it has not, it writes the new record and returns.
// If the primary data record has been used, it then checks to see if either the
// primary record or some record is overflow matches the key to the new record, and
// if a match is found, it reports this and returns.
// While searching for a match, the program records the first deleted record so that it
// might be used again.
// If no match is found, and a deleted record was found, the new record is written over
// the deleted record and the function returns. If no deleted record was found
// the overflow pointer is accessed, the new record written to overflow, and the overflow
// pointer incremented.
void Insert()
{
int ioDeleteRecordPointer = 0; // Pointer to the address of the first deleted record
// Data accepted from CIN
char sInSSN[10], sInName[21];
float nInSalary;
int nDeleteSwitch;
// Data from the record being examined
char sSSN[10], sName[21]; /* emp record read from file */
float nSalary;
int nSSN; /* integer value of primary key string sInSSN */
int nHashKey; /* hash value = (key % 10) */
long nFileOffset; /* offset */
mioHashFile = fopen ("emp", "r+");
//Get the overflow header from the file
fscanf (mioHashFile,"%d",&mnOverlowRecords);
cout << "Please enter SSN, name and salary separated by blanks\n";
cin >> sInSSN >> sInName >> nInSalary;
// convert primary key string to integer by folding and then division
nSSN = AddDigits(sInSSN);
nHashKey = nSSN % 10;
// calculate the address in the file for the primary record, set the file pointer
// there and read the record
nFileOffset = (nHashKey *mnRecordLength) + mnHeaderSize;
fseek (mioHashFile, nFileOffset, 0);
fscanf (mioHashFile, "%d%s%s%f", &nDeleteSwitch, sSSN, sName, &nSalary);
if (nDeleteSwitch == -1) // virgin record, insert immediately
{
fseek (mioHashFile, nFileOffset, 0);
fprintf(mioHashFile,"%3d%10s%21s%10.2f\n", 0, sInSSN, sInName, nInSalary);
fclose (mioHashFile);
printf ("insert complete\n");
return;
}
// A live record with the same SSN - Report it and get out
if (nDeleteSwitch == 0 && strcmp(sInSSN,sSSN)==0)
{
printf ("SSN already in file, insert terminated\n");
fclose (mioHashFile);
return;
}
// Found deleted record. Use ioDeleteRecordPointer to remember it.
if (nDeleteSwitch == 1)
{
ioDeleteRecordPointer = nFileOffset;
}
// Search through overflow to see if the record exists there
for (int nRecords = 0; nRecords < mnOverlowRecords; nRecords++)
{
nFileOffset = ((nRecords + 10) * mnRecordLength) + mnHeaderSize;
fseek (mioHashFile, nFileOffset, 0);
fscanf (mioHashFile, "%d%s%s%f", &nDeleteSwitch, sSSN, sName, &nSalary);
// Duplicate primary key in overflow area. Abort insert.
if (nDeleteSwitch == 0 && strcmp(sInSSN,sSSN)==0)
{
printf("SSN already in file, insert terminated\n");
fclose (mioHashFile);
return;
}
// Found a deleted record. If we don't already have one, set the deleted record pointer
if ( ioDeleteRecordPointer == 0 && nDeleteSwitch == 1)
{
ioDeleteRecordPointer =nFileOffset;
}
} //next nRecords
// We are now here, so we have searched through primary and overflow and
// did not find a duplicate SSN
// See if we found a deleted record we can reuse
if (ioDeleteRecordPointer != 0 )
{
fseek (mioHashFile, ioDeleteRecordPointer, 0);
fprintf(mioHashFile,"%3d%10s%21s%10.2f\n", 0, sInSSN, sInName, nInSalary);
}
// No deleted record. Get the next overflow record, create it and update the Overlow HEader
else
{
fseek (mioHashFile, (mnOverlowRecords + 10) * mnRecordLength + mnHeaderSize, 0);
fprintf(mioHashFile,"%3d%10s%21s%10.2f\n", 0, sInSSN, sInName, nInSalary);
rewind (mioHashFile); /* go back and update header in overflow */
fprintf(mioHashFile, "%4d\n", ++mnOverlowRecords); /* update overflow file size */
}
// All done - Say Goodbye!!
fclose(mioHashFile);
printf("insert complete \n");
return;
}
// This function simply uses the DOS Type command to dump the contents of the file
void Dump()
{
printf("emp\n");
system("type emp");
return;
}
// The Find Function is passed a social security number key
// It will look through the primary and overflow records for a
// the same key and if found pass back a file pointer to the beginning
// of that record. If nothing is found, a zero is passed back.
FILE * find(char * psSSN) /* key is pointer to SSN */
{
int nSSN, nHashKey;
long nFileOffset;
int nDeleteSwitch;
char sSSN[10], sName[21];
float nSalary;
nSSN = AddDigits(psSSN);
nHashKey = nSSN % 10; /* calculate hash value */
nFileOffset = nHashKey * (mnRecordLength) + mnHeaderSize; /* convert slot number to offset */
mioHashFile = fopen("emp", "r+");
// Read in the current overflow counter
fscanf (mioHashFile,"%d",&mnOverlowRecords);
//Go to the hashed data record
fseek (mioHashFile, nFileOffset, 0);
fscanf (mioHashFile, "%d", &nDeleteSwitch); /* read delete flag */
// If we hashed to a virgin record, then key not in table - Return 0
if (nDeleteSwitch == -1)
{
fclose (mioHashFile);
return 0;
}
fscanf(mioHashFile, "%s", sSSN); /* read ssn */
// If this is a live record and the keys match, set file pointer back to the beginning and pass it back
if (nDeleteSwitch == 0 && (strcmp(psSSN,sSSN) == 0))
{
fseek (mioHashFile, nFileOffset, 0);
return mioHashFile;
}
// Not found in primary. Switch to overflow going through it sequentially
fseek (mioHashFile, 10*mnRecordLength + mnHeaderSize, 0);
for (int nRecords = 0; nRecords < mnOverlowRecords; nRecords++)
{
nFileOffset = ftell (mioHashFile); /* remember the position of next record */
fscanf (mioHashFile, "%d%s%s%f", &nDeleteSwitch, sSSN, sName, &nSalary); /* read entire
record to get past it for next iteration */
if (nDeleteSwitch == 0 && (strcmp (psSSN,sSSN) == 0)) /* record found, return
open file pointer */
{
fseek (mioHashFile, nFileOffset, 0);
return mioHashFile;
}
}
// Record not found. Close file and return 0
fclose (mioHashFile);
return 0;
}
// The Retreive Function uses the Find Command to set the file pointer
// at the appropriate record. It then reads the record and prints out
// the data in the record.
void Retrieve()
{
char sInSSN[10];
int nDeleteSwitch;
char sSSN[10], sName[21];
float nSalary;
printf("Please enter SSN\n");
scanf ("%s", sInSSN);
mioHashFile = find(sInSSN);
if (mioHashFile == 0)
{
printf("SSN not found\n");
return;
}
fscanf (mioHashFile, "%d%s%s%f", &nDeleteSwitch, sSSN, sName, &nSalary);
printf ("ssn = %s name = %s salary = %10.2f\n", sSSN, sName, nSalary);
fclose(mioHashFile);
printf ("retrieve complete\n");
return;
}
// The Delete function calls the Find Function. If Find returns
// an active file pointer, then the routine updates the
// the delete flag for location returned.
void Delete()
{
char sSSN[10];
printf("Please enter the SSN of the employee to be fired.\n");
scanf ("%s", sSSN);
//find returns 0 or open file pointer positioned to beginning of found employee record
mioHashFile = find (sSSN);
// employee not found
if (mioHashFile == 0)
{
printf("Employee does not exist.\n");
return;
}
// employee found, set delete flag for employee
fprintf (mioHashFile, "%3d", 1);
fclose(mioHashFile);
printf("Firing complete.\n");
return;
}
//This function prints out all the records in the employee file including
//primary and overflow records.
void Print()
{
int nDeleteSwitch;
char sSSN[10], sName[21];
float nSalary;
printf("SSN NAME SALARY\n");
mioHashFile = fopen("emp", "r");
fscanf (mioHashFile,"%d",&mnOverlowRecords);
fseek (mioHashFile, mnHeaderSize, 0); //Skip past the CRLF at end of overflow counter
/* sequentially print all active records */
for(int i=0;i<10+mnOverlowRecords;i++)
{
fscanf(mioHashFile,"%d%s%s%f",&nDeleteSwitch,sSSN,sName,&nSalary);
if (nDeleteSwitch==0)printf("%-11s%-21s%-10.2f\n",sSSN,sName,nSalary);
}
fclose(mioHashFile);
printf("Print Table Complete\n");
return;
}
// This function is used to Fold the entered SSN
int AddDigits(char * psSSN)
{
int nSSN = 0;
for ( int nChar = 0; psSSN[nChar]!=0 ; nChar++)
{
nSSN = nSSN + psSSN[nChar];
}
return nSSN;
}