C-Labs/assessment2employee/employee3.c
2019-02-09 18:50:58 +00:00

392 lines
9.7 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* maximum number of employees that can be stored at once (relevant only
to storage using an array) */
#define MAX_EMPLOYEES 200
#define MAX_NAME_LENGTH 100
#define MAX_JOB_LENGTH 100
/* Employee structure
*/
struct Employee
{
/* Employee details */
char name[MAX_NAME_LENGTH+1]; /* name string */
char sex; /* sex identifier, either 'M' or 'F' */
int age; /* age */
char job[MAX_JOB_LENGTH+1]; /* job string */
/* pointers to previous and next employee structures in the linked list
(for if you use a linked list instead of an array) */
struct Employee *prev, *next;
};
typedef struct Employee emp;
emp *list_root = NULL;
/* read_line():
*
* Read line of characters from file pointer "fp", copying the characters
* into the "line" string, up to a maximum of "max_length" characters, plus
* one for the string termination character '\0'. Reading stops upon
* encountering the end-of-line character '\n', for which '\0' is substituted
* in the string. If the end of file character EOF is reached before the end
* of the line, the failure condition (-1) is returned. If the line is longer
* than the maximum length "max_length" of the string, the extra characters
* are read but ignored. Success is returned (0) on successfully reading
* a line.
*/
static int read_line ( FILE *fp, char *line, int max_length )
{
int i;
char ch;
/* initialize index to string character */
i = 0;
/* read to end of line, filling in characters in string up to its
maximum length, and ignoring the rest, if any */
for(;;)
{
/* read next character */
ch = fgetc(fp);
/* check for end of file error */
if ( ch == EOF )
return -1;
/* check for end of line */
if ( ch == '\n' )
{
/* terminate string and return */
line[i] = '\0';
return 0;
}
/* fill character in string if it is not already full*/
if ( i < max_length )
line[i++] = ch;
}
/* the program should never reach here */
return -1;
}
/* read_string():
*
* Reads a line from the input file pointer "fp", starting with the "prefix"
* string, and filling the string "string" with the remainder of the contents
* of the line. If the start of the line does not match the "prefix" string,
* the error condition (-1) is returned. Having read the prefix string,
* read_string() calls read_line() to read the remainder of the line into
* "string", up to a maximum length "max_length", and returns the result.
*/
static int read_string ( FILE *fp,
char *prefix, char *string, int max_length )
{
int i;
/* read prefix string */
for ( i = 0; i < strlen(prefix); i++ )
if ( fgetc(fp) != prefix[i] )
/* file input doesn't match prefix */
return -1;
/* read remaining part of line of input into string */
return ( read_line ( fp, string, max_length ) );
}
/* Moved sorting into separate function so it could be called by either add employee
or read database function */
static void insert_employee(emp* newemp){
if(list_root == NULL){
newemp->prev = NULL;
newemp->next = list_root;
list_root = newemp;
}else{
if(strcmp(newemp->name, list_root->name) < 1){
newemp->prev = NULL;
newemp->next = list_root;
list_root = newemp;
}else{
emp* marker = list_root;
while(marker->next != NULL){
marker = marker->next;
}
if(strcmp(newemp->name, marker->name) > 0){
marker->next = newemp;
newemp->prev = marker;
newemp->next = NULL;
}else{
marker = list_root;
while(marker->next != NULL){
if(strcmp(newemp->name, marker->name) > 0 && strcmp(newemp->name, marker->next->name) <= 0){
newemp->next = marker->next;
newemp->prev = marker;
marker->next->prev = newemp;
marker->next = newemp;
}
marker = marker->next;
}
}
}
}
}
/* menu_add_employee():
*
* Add new employee to database
*/
static void menu_add_employee(void)
{
/* fill in the code here in part 1, and add any extra functions you need */
emp *newemp;
newemp = (emp *)malloc(sizeof(emp));
fprintf(stderr, "Enter Name: ");
read_line(stdin, newemp->name, MAX_NAME_LENGTH + 1);
char gender;
for(;;){
fprintf(stderr, "Enter Gender: ");
gender = getchar();
if(gender == '\n') gender = getchar();
if(gender == 'F' || gender == 'M') break;
fprintf(stderr, "Enter either M or F\n");
}
newemp->sex = gender;
int age;
for(;;){
fprintf(stderr, "Enter Age: ");
scanf("%i", &age);
if(age > 0) break;
fprintf(stderr, "Enter a Positive Integer\n");
}
newemp->age = age;
getchar();
fprintf(stderr, "Enter Job: ");
read_line(stdin, newemp->job, MAX_JOB_LENGTH + 1);
insert_employee(newemp);
}
/* menu_print_database():
*
* Print database of employees to standard output.
*/
static void menu_print_database(void)
{
/* fill in the code here in part 1, and add any extra functions you need */
if(list_root != NULL){
emp* marker = list_root;
do{
printf("Name: %s\n", marker->name);
printf("Sex: %c\n", marker->sex);
printf("Age: %i\n", marker->age);
printf("Job: %s\n\n", marker->job);
marker = marker->next;
}while(marker->name != NULL);
}else{ fprintf(stderr, "Nothing To Print"); }
}
/* menu_delete_employee():
*
* Delete new employee from database.
*/
static void menu_delete_employee(void)
{
/* fill in the code here in part 2, and add any extra functions you need */
fprintf(stderr, "Enter Name To Be Deleted: ");
char name[MAX_NAME_LENGTH + 1];
read_line(stdin, name, MAX_NAME_LENGTH + 1);
int found = 0;
emp* marker = list_root;
for(;;){
if(strcmp(marker->name, name) == 0){
if(list_root == marker){ //FIRST EMPLOYEE
if(marker->next == NULL){
free(marker);
list_root = NULL;
}else{
list_root = marker->next;
marker->next->prev = NULL;
free(marker);
}
}else{
if(marker->next == NULL){//LAST EMPLOYEE
marker->prev->next = NULL;
free(marker);
}else{
marker->prev->next = marker->next;
marker->next->prev = marker->prev;
free(marker);
}
}
found = 1;
break;
}else{
if(marker->next != NULL){
marker = marker->next;
}else{
break;
}
}
}
if(found = 0) fprintf(stderr, "Name not Found\n");
getchar();
}
/* read file containing database of employees */
static void read_employee_database ( char *file_name )
{
/* fill in the code here in part 3, and add any extra functions you need */
FILE *empfile;
empfile = fopen(file_name, "r");
if(empfile == NULL){ /* Checks file has opened correctly */
fprintf(stderr, "Error Opening %s File to Read", file_name);
exit(EXIT_FAILURE);
}
for(;;){ /*Infinite loop that reads in employees until can't read any more*/
emp* newemp;
newemp = (emp *)malloc(sizeof(emp));
int name_check = read_string(empfile, "Name: ", newemp->name, MAX_NAME_LENGTH+1);
if(name_check == -1) break; /* This line exits loop when no new name can be found */
char gender[2]; /* sends string to be read to */
read_string(empfile, "Sex: ", gender, 2);
if(gender[0] != 'M' && gender[0] != 'F'){ /* Gender Check */
fprintf(stderr, "Incorrect Gender Format Found For Employee %s\n", newemp->name);
exit(EXIT_FAILURE);
}
newemp->sex = gender[0]; /* Takes first character of array for gender char */
int age;
char char_age[10];
read_string(empfile, "Age: ", char_age, 10);
age = atoi(char_age); /* Uses function to cast string as int, read_string only reads to strings */
if(age < 1){
fprintf(stderr, "Negative Age Found For Employee %s\n", newemp->name);
exit(EXIT_FAILURE);
}
newemp->age = age;
read_string(empfile, "Job: ", newemp->job, MAX_JOB_LENGTH+1);
insert_employee(newemp); /* Correctly sorts and inserts employee */
char carriage[2];
read_line(empfile, carriage, 1); /* Important line to skip blank line inbetween employees */
}
fclose(empfile); /* Close File */
}
/* codes for menu */
#define ADD_CODE 0
#define DELETE_CODE 1
#define PRINT_CODE 2
#define EXIT_CODE 3
int main ( int argc, char *argv[] )
{
/* check arguments */
if ( argc != 1 && argc != 2 )
{
fprintf ( stderr, "Usage: %s [<database-file>]\n", argv[0] );
exit(-1);
}
/* read database file if provided, or start with empty database */
if ( argc == 2 )
read_employee_database ( argv[1] );
for(;;)
{
int choice, result;
char line[301];
/* print menu to standard error */
fprintf ( stderr, "\nOptions:\n" );
fprintf ( stderr, "%d: Add new employee to database\n", ADD_CODE );
fprintf ( stderr, "%d: Delete employee from database\n", DELETE_CODE );
fprintf ( stderr, "%d: Print database to screen\n", PRINT_CODE );
fprintf ( stderr, "%d: Exit database program\n", EXIT_CODE );
fprintf ( stderr, "\nEnter option: " );
if ( read_line ( stdin, line, 300 ) != 0 ) continue;
result = sscanf ( line, "%d", &choice );
if ( result != 1 )
{
fprintf ( stderr, "corrupted menu choice\n" );
continue;
}
switch ( choice )
{
case ADD_CODE: /* add employee to database */
menu_add_employee();
break;
case DELETE_CODE: /* delete employee from database */
menu_delete_employee();
break;
case PRINT_CODE: /* print database contents to screen
(standard output) */
menu_print_database();
break;
/* exit */
case EXIT_CODE:
break;
default:
fprintf ( stderr, "illegal choice %d\n", choice );
break;
}
/* check for exit menu choice */
if ( choice == EXIT_CODE )
break;
}
return 0;
}