Functions for the above C program are given below ...
/* Function definitions ... */
char* getLine( FILE* fp )
{
int c, i=0;
char* buffer = (char*) calloc( maxStringLen+1, 1 );
myAssert( (buffer!=NULL), "Error: calloc failed to allocate memory" );
buffer[0] = 0; /* NULL terminate 'as we go' ... */
/* eats up WHOLE line ... including '\n' */
while( (c=fgetc(fp)) != EOF && c != '\n' )
{
if( i<maxStringLen )
{
buffer[i] = c;
++i;
buffer[i] = 0;
}
}
buffer = (char*) realloc( buffer, i+1 );
myAssert( (buffer!=NULL), "Error: realloc failed to allocate memory" );
return buffer;
}
/*
char* newCopy( char* str )
{
int i, len=strlen( str );
//while( str[len]!=0 ) ++len;
char * nCopy = (char*) malloc( len+1 );
myAssert( (nCopy!=-NULL), "Error: malloc failed to allocate memory" );
for( i=0; i<len; ++i ) nCopy[i] = str[i];
nCopy[len] = 0;
return nCopy;
}
*/
/* Return a pointer to the Student if ID found in list; else return NULL */
pStudent pID( int n )
{
pStudent p = phead;
if( p==NULL )
return NULL; /* List empty ... so all id numbers are available */
while( p!=NULL )
{
if( p->id == n )
return p; /* id number entered was already used */
/* Else ... get next p to compare */
p = p->next;
}
/* If reach here ... then id number not in list so ... */
return NULL;
}
void flushStdin()
{
while( getchar() != '\n' );
}
void exitNowYes()
{
int c, quit;
printf("\nPress 'X' to eXit ... ");
c = quit = getchar();
while(c != '\n') c=getchar(); /* flush stdin ... */
if( quit=='x' || quit=='X' )
{
if( fileFlag ) writeAllToFile();
printf("\nPress 'Enter' to exit right now ... ");
if( (c=getchar()) == '\n' ) exit(0);
else while(c != '\n') c=getchar(); /* flush stdin ... */
}
}
void add() /* ... and insert in the proper place in the list. */
{
pStudent pS;
int ID = 0;
printf("Enter ID : ");
scanf("%d", &ID); flushStdin();
if( pID(ID) || ID<=0 ) /* if pointer returned is NOT NULL, id IS used */
{
printf("\nid %d is NOT available.\n", ID );
return; /* Exit to menu right now ... */
}
/* If program reaches here, the ID just entered is available to use. */
pS = (pStudent) malloc(sizeof(Student));
myAssert( (pS!=NULL), "Error: malloc failed to allocte memory" );
pS->id = ID;
printf("Enter Last Name : ");
pS->last = getLine(stdin);
printf("Enter First Name : ");
pS->first = getLine(stdin);
printf("Enter Test1 : ");
scanf( "%f", &pS->test1 ); flushStdin();
printf("Enter Test2 : ");
scanf( "%f", &pS->test2 ); flushStdin();
printf("Enter Assignment : ");
scanf( "%f", &pS->assignment ); flushStdin();
printf("Enter Lab Test : ");
scanf( "%f", &pS->labtest ); flushStdin();
printf("Enter Final Exam : ");
scanf( "%f", &pS->finalexam ); flushStdin();
/* Set up link to this node */
insert( pS );
}
/* insert in list with last & first names in proper order */
void insert( pStudent pS )
{
/* Firstly, we handle the case where 'this' should be the first element. */
if(phead == NULL || StudentCmp(pS, phead) < 0)
{
/* So ... it now becomes the first element ... */
pS->next = phead; /* old phead becomes 2nd in list ... */
phead = pS; /* and ... this pS ... becomes the head of the list */
}
else /* If here ... search the linked list for the right location ... */
{
pStudent q = phead; /* Get a working copy of phead in q */
/* Start comparing with element AFTER 'q' ... i.e. the 'next in' ... */
while(q->next != NULL && StudentCmp(q->next, pS) <= 0)
{
q = q->next; /* Traverse the list ... */
}
/*
Ok, insert after 'q' by relinking the pointers (similar to above)
( Includes inserting at end position ... where q->next == NULL )
*/
pS->next = q->next; /* Inserted 'pS' is linked to 'upstream element' */
q->next = pS; /* Now 'q' is updated to link to the new 'pS' element */
}
/* Update global variables. */
++numStudents;
fileFlag = 1;
}
void showAll()
{
pStudent p = phead;
int c;
if (phead==NULL)
{
puts("\nNo records in memory at present.") ;
return;
}
/* If reach here ... */
while( p!=NULL )
{
view( p );
printf("\nPress 'Enter' to continue ... or enter 'A' to abort ... ");
if( (c=getchar()) == 'a' || c == 'A' )
{
flushStdin();
return;
}
while(c != '\n') c=getchar(); /* flush stdin ... */
p = p->next;
}
}
void viewEdit()
{
int yes = 0, ID = 0;
pStudent p;
printf("Enter the id number to View/Edit : ");
scanf("%d",&ID); flushStdin();
p = pID(ID); /* See if pointer exists; i.e. get value or NULL */
if( p ) /* i.e. if pointer returned above was not NULL ... */
{
view(p);
printf("\nEdit (y/n) ? ");
yes = getchar();
if( yes=='y' || yes=='Y' )
{
while( yes!='\n' ) yes=getchar(); /* flush stdin */
edit(p);
}
else while( yes!='\n' ) yes=getchar(); /* flush stdin */
}
else printf("\nStudent with ID number %d not found.\n", ID);
}
void view(pStudent pS)
{
printf
(
"ID number : %d\n"
"Last Name : %s\n"
"First Name : %s\n"
"Test 1 : %.2f\n"
"Test 2 : %.2f\n"
"Assignment : %.2f\n"
"Lab Test : %.2f\n"
"Final Exam : %.2f\n",
pS->id, pS->last, pS->first,
pS->test1, pS->test2, pS->assignment,
pS->labtest, pS->finalexam
);
}
void edit(pStudent pS)
{
int ID = 0;
int idTmp = pS->id; /* Firstly get a backup copy of this id ... */
pS->id = -1; /* Now ... reset old id number to a dummy value ... */
printf("Edit ID : ");
scanf("%d", &ID); flushStdin();
if( pID(ID) ) /* i.e. if pointer returned is not NULL, this 'ID' IS USED */
{
printf("\nid %d is NOT available.\n", ID );
pS->id = idTmp; /* Restore the id since this pS was NOT edited */
return; /* Exit to menu right now ... */
}
/* If reach hear ... */
del(pS);/* Delete old record ... etc */
pS = (pStudent) malloc(sizeof(Student)); /* get new memory for new record */
myAssert( (pS!=NULL), "Error: malloc failed to allocte memory");
pS->id = ID;
printf("Edit Last Name : ");
pS->last = getLine(stdin);
printf("Edit First Name : ");
pS->first = getLine(stdin);
printf("Edit Test1 : ");
scanf( "%f", &pS->test1 ); flushStdin();
printf("Edit Test2 : ");
scanf( "%f", &pS->test2 ); flushStdin();
printf("Edit Assignment : ");
scanf( "%f", &pS->assignment ); flushStdin();
printf("Edit Lab Test : ");
scanf( "%f", &pS->labtest ); flushStdin();
printf("Edit Final Exam : ");
scanf( "%f", &pS->finalexam ); flushStdin();
insert( pS );
}
void viewDel()
{
pStudent p;
int yes = 0, ID = 0;
printf("Enter the id number to View/Delete : ");
scanf("%d",&ID); flushStdin();
p = pID(ID); /* See if pointer exists; i.e. get value or NULL */
if( p ) /* i.e. if pointer returned above was not NULL ... */
{
view(p);
printf("\nDelete (y/n) ? ");
yes = getchar();
if( yes=='y' || yes=='Y' ) { del(p); fileFlag = 1; }
while( yes!='\n' ) yes=getchar(); /* flush stdin */
}
else printf("\nStudent with ID number %d not found.\n", ID);
}
void del(pStudent pS)
{
pStudent p,
pp; /* to hold the pointer to the previous record */
/* Handle special case of 'first in list' */
if( pS==phead )
{
phead = pS->next;
free( pS->first );
free( pS->last );
free( pS );
--numStudents; /* update globals ... */
fileFlag = 1;
return;
}
/* Else not first in list, so ... */
p = phead; /* set p to this initial value to start loop */
/* Now find the pointer to the previous record. */
while( p != pS )
{
pp = p; /* pp holds previous pointer value ... */
p = p->next; /* set to next pointer in link list chain */
}
/*
Now we have a pointer to the previous Student record, so ...
we can now point that previous record to one past this pS record
*/
pp->next = pS->next;
/* Now free the memory for this record and update the globals ... */
free( pS->first );
free( pS->last );
free( pS);
--numStudents;
fileFlag = 1;
}
void delAll()
{
pStudent p = phead; /* Set p to this initial value to start loop */
pStudent pNext; /* To hold the pointer to the next record */
while( p != NULL )
{
pNext = p->next; /* Get a pointer to the next record. */
free( p->first );
free( p->last );
free( p );
p = pNext; /* Update p ... */
}
/* Update globals ... */
phead = NULL;
numStudents = 0;
fileFlag = 0;
}
/* Note: calling delAll() here ... will re-set globals as above ... */
void init()
{
int yes;
if( phead != NULL )
{
printf("\nDo you wish to overwrite the records in memory y/n ? ");
yes = getchar();
if( yes=='y' || yes=='Y' )
delAll(); /* re-sets globals ... */
else
{
if(numStudents==1)
puts("1 Student record was left intact in memory.");
else
printf("%d Student records were left intact in memory.\n",
numStudents);
}
while( yes!='\n' ) yes=getchar(); /* flush stdin */
}
else puts("\nThere were no records in memory to clear.");
}
void scramble( char s[] )
{
int i = 0;
int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
while( s[i]!=0 ) { s[i] = (char) ((int)s[i] - code[i]); ++i; }
}
void unscramble( char s[] )
{
int i = 0;
int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
while( s[i]!=0 ) { s[i] = (char) ((int)s[i] + code[i]); ++i; }
}
void writeAllToFile()
{
if( !fileFlag ) return;
if( numStudents == writeFile() )
{
if( numStudents > 0 )
{
if( numStudents == 1 )
puts("\nThe 1 Student record was safely filed.");
else
printf
(
"\nAll %d Student records safely filed.\n",
numStudents
);
}
}
else
{
printf
(
"\nAn error occured while filing the Student records."
"\nPlease see the programmer for help with the problem.\n"
"\nExiting the program now. Press 'Enter' to continue ... "
);
flushStdin(); /* Holds window open to show above message. */
exit(0); /* Return error number to system. */
}
}
int writeFile()
{
int count; /* to track the records actually written to the file */
FILE* fp;
pStudent p = phead;
if( phead==NULL )
{
puts("\nNo records available ... so NO records written to file.") ;
return 0;
}
fp = fopen( fName, "w" );
if( fp==NULL )
{
printf("\nError opening file %s. Press 'Enter' to continue ... ", fName);
flushStdin();
return 0;
}
count = 0; /* to track the records actually written to the file */
while( p!=NULL )
{
fprintf
(
fp,
"%d\n"
"%s\n"
"%s\n"
"%.2f\n"
"%.2f\n"
"%.2f\n"
"%.2f\n"
"%.2f\n",
p->id, p->last, p->first,
p->test1, p->test2, p->assignment,
p->labtest, p->finalexam
);
++count;
p = p->next;
}
fclose( fp );
fileFlag = 0;
return count; /* Number of records written. */
}
int readFile()
{
int count, ID;
/* char buffer[maxStringLen+1]; */
FILE *fp;
pStudent pS;
#if !sortRead
pStudent pp=NULL;
#endif
fp = fopen( fName, "r" );
if( fp==NULL )
{
printf
(
"\nError opening file %s.\n"
"Perhaps it hasn't been created yet?\n"
"Press 'Enter' to continue ... ",
fName
);
flushStdin();
return 0;
}
/* BUT!!! may need to delete any records in memory first. */
init();
/*
NOTE: we need phead to be equal to NULL in the following ...
to be permitted to set phead ...
to point to the first Student record in memory (read in from the file).
*/
if( phead != NULL ) /* then exit with message ... */
{
if(numStudents==1)
puts("\nThe 1 former Student record was left in memory.");
else
printf("\nThe %d former Student records were left in memory.\n", numStudents);
return 0; /* So ...old count of Student records will NOT be updated. */
}
/* If the program reaches here ... then ... */
count = 0;
while( fscanf( fp, "%d", &ID) != EOF )
{
pS = (pStudent) malloc(sizeof(Student));
pS->id = ID;
//fscanf( fp, "%s", buffer );
//pS->last = newCopy( buffer );
fgetc(fp); /* eats up the '\n' char left over from above 'ID read' */
pS->last = getLine(fp);
//fscanf( fp, "%s", buffer );
//pS->first = newCopy( buffer );
pS->first = getLine(fp);
fscanf( fp, "%f", &pS->test1 );
fscanf( fp, "%f", &pS->test2 );
fscanf( fp, "%f", &pS->assignment );
fscanf( fp, "%f", &pS->labtest );
fscanf( fp, "%f", &pS->finalexam );
#if !sortRead
if ( pp != NULL ) /* for 2nd and up records ...*/
pp->next = pS; /* now previous record points to this new one */
else phead =pS; /* first record only has base pointer */
pS->next = 0; /* NULL terminate list ... */
pp = pS; /* Keep a copy of address of this pS in pp for next while loop. */
#else
insert( pS );
#endif
++count;
/* printf( "\nRecord number is %d\n", count ); */
}
fclose( fp );
if(count==1)
puts("\n1 record was read into memory from the disk file.");
else
printf("\n%d records were read into memory from the disk file.\n", count);
fileFlag = 0;
return count; /* Total number of Student records found in the file. */
}
int passWord()
{
/*
Get the password in the file, if it exists, into buffer2
and compare it with the user entry in buffer1.
*/
char *buffer1;
char buffer2[maxStringLen+1];
int attempts;
int pwOK = 0;
FILE *fp = fopen(fPW, "r");
if(fp==NULL) /* i.e. if file fPW doesn't exit ... */
{
pwOK = newPW(); /* get new password ...*/
if( pwOK == 1 ) return 1; /* report this match of passwords back ...*/
}
else /* File fPW does exist ... so ... */
{
/* Get file password into a string in buffer2. */
fscanf( fp, "%s", buffer2 );
fclose( fp );
unscramble( buffer2 );
/* Now ... get password entered by user into a string in buffer1. */
for( attempts=0; attempts<3; ++attempts )
{
printf("Enter password: ");
//scanf( "%s", buffer1 ); flushStdin();
buffer1 = getLine(stdin);
if(strcmp(buffer1, buffer2)==0) /* If true ... passwords matched. */
{
puts( "Match!\n" );
free( buffer1 );
return 1; /* Report this match of passwords back ...*/
}
free( buffer1 );
}
}
/* if reach here ...*/
printf( "NO MATCH! ... Press 'Enter' to exit ... " );
flushStdin();
exit(1); /* Quit the program right now ... */
}
int newPW()
{
FILE* fp;
char* buffer1;
char* buffer2;
for(;;)
{
/* Get the new password into a string in buffer1. */
printf("Enter the new password (8 to 20 characters): ");
buffer1 = getLine(stdin); /* a max of maxStringLen char's */
if( strlen(buffer1) >= minPWLen )
break;
printf("Your password must be at least %d characters ...\n", minPWLen );
free( buffer1 ); /* ... and try again ...*/
}
/*
Get a 'verify copy' of the new password into buffer2
and compare it with the password in buffer1.
*/
printf("Enter the new password again: ");
buffer2 = getLine(stdin);
if(strcmp(buffer1, buffer2)==0) /* If true ... passwords matched. */
{
fp = fopen(fPW, "w");
if(fp==NULL)
{
printf("Error opening file %s ... Press 'Enter' to exit ... ", fPW);
flushStdin();
free(buffer2);
free(buffer1);
exit(2);
}
else
{
puts( "Match!\n" );
scramble(buffer1);
fprintf( fp, "%s", buffer1 );
fclose( fp );
free(buffer2);
free(buffer1);
return 1; /* Report this match of passwords back ...*/
}
}
/* If reach here ...*/
printf( "NO MATCH! ... Press 'Enter' to exit ... " );
flushStdin();
free(buffer2);
free(buffer1);
exit(3); /* Quit the program right now ... */
}
/* A function to compare two Student records to permit sorting ... */
int StudentCmp( pStudent pS1, pStudent pS2 )
{
int compare = strcmp(pS1->last, pS2->last);
if ( compare == 0 )
return strcmp(pS1->first, pS2->first);
return compare;
}