Code:
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define LINESIZE 1024
/*
- Returns 1 if the string s consists entirely of alphabets; otherwise, returns 0.
*/
int str_all_alphabets(const char s[]) {
size_t i;
for(i = 0; s[i] != '\0'; i++)
if(!isalpha((int)s[i]))
return 0;
return 1;
}
/*
- Converts all characters in the array to lowercase.
*/
void str_lowercase(char s[]) {
size_t i;
for(i = 0; s[i] != '\0'; i++)
s[i] = tolower((int)s[i]);
}
/*
- Returns the length of the array.
*/
size_t str_length(char s[]) {
size_t length;
length = strlen(s);
return length;
}
/*
- Counts the number of characters in the file and divides that number by 36
- to determine the total number of records in the file.
*/
size_t count_records(FILE *ifp) {
int char_count = 0;
int num_records;
int c;
if(fseek(ifp, 0, SEEK_SET) != 0)
perror("fseek");
while(1) {
c = fgetc(ifp);
if(c == EOF)
break;
char_count++;
}
num_records = char_count / 36;
return num_records;
}
/*
- Return 0 on end-of-file or if the integer -1 is read, or 1 if a name is successfully
- read & stored in the array word of n characters.
*/
int get_name(const char prompt[], char word[], size_t n) {
char line[LINESIZE];
char holder[LINESIZE];
int int_holder[LINESIZE];
while(1) {
printf("%s", prompt);
if(!fgets(line, LINESIZE, stdin)) {
clearerr(stdin);
break;
}
if(sscanf(line, "%d", int_holder) == 1)
if(int_holder[0] == (int)-1)
return 0;
if(sscanf(line, "%s", holder) == 1) {
if(strlen(holder) < n) {
if(str_all_alphabets(holder) != 0) {
strcpy(word, holder);
return 1;
}
}
}
}
return 0;
}
/*
- Returns max + 1 on end-of-file or if the integer -1 is read, or the integer read
- from the user if it is between min & max inclusive.
*/
int get_score(const char prompt[], int min, int max, int *score) {
char line[LINESIZE];
int n;
while(1) {
printf(prompt);
if(!fgets(line, LINESIZE, stdin)) {
clearerr(stdin);
return max + 1;
}
if(sscanf(line, "%d", &n) == 1) {
if(n == -1)
return max + 1;
if(n >= min && n <= max) {
*score = n;
return n;
}
}
}
}
/*
- Prints a single record stored in the file pointed to by ifp.
*/
void print_record(FILE *ifp, int record) {
char record_array[36];
size_t i;
int break_count = 0;
char cur_char;
char prev_char = '\0';
int file_location = 36 * (record - 1);
if(fseek(ifp, file_location, SEEK_SET) != 0)
perror("fseek");
fread(record_array, 1, 36, ifp);
for(i = 0; record_array[i] != '\0'; i++) {
cur_char = record_array[i];
if(cur_char != ' ')
printf("%c", record_array[i]);
else if(cur_char == ' ' && isalpha((int)prev_char)) {
if(break_count == 1)
printf(": ");
else if(break_count == 0) {
printf(", ");
break_count++;
}
}
prev_char = cur_char;
}
printf("\n");
}
/*
- Appends the name portion of a record to the end of the file pointed to by ifp.
*/
void append_records_name(FILE *ifp, char name[]) {
if(fseek(ifp, 0, SEEK_END) != 0)
perror("fseek");
str_lowercase(name);
fprintf(ifp, "%15s", name);
fprintf(ifp, " ");
}
/*
- Appends the score portion of a record to the end of the file pointed to by ifp.
*/
void append_records_score(FILE *ifp, int score) {
if(fseek(ifp, 0, SEEK_END) != 0)
perror("fseek");
fprintf(ifp, "%3d", score);
fprintf(ifp, " ");
}
/*
- Prompts the user to choose one of the three options.
- The user can either append a record, print a single record, or print
- all records from a certain record number. The program continuously prompts users
- for further commands until the user quits with the end-of-file key.
*/
void program_structure(FILE *ifp) {
size_t i;
int c;
char line[LINESIZE];
char first_name_input[15];
char last_name_input[15];
int score = 0;
int first_name_success = 0;
int last_name_success = 0;
int score_success = 0;
size_t num_records;
while(1) {
fprintf(stderr, "Enter a command: \n");
fprintf(stderr, "Enter 0 to append a record \n");
fprintf(stderr, "Enter a negative integer to display all records from that record number to the end \n");
fprintf(stderr, "Enter a positive integer to display that chosen record \n");
if(!fgets(line, LINESIZE, stdin)) {
clearerr(stdin);
break;
}
if(sscanf(line, "%d", &c) == 1) {
num_records = count_records(ifp);
if(c == 0) {
if(get_name("Please enter a last name: ", last_name_input, 15) != 0)
last_name_success = 1;
else
continue;
if(get_name("Please enter a first name: ", first_name_input, 15) != 0)
first_name_success = 1;
else
continue;
if(get_score("Please enter a score between 0 and 100 inclusive: ", 0, 100, &score) != 101)
score_success = 1;
else
continue;
if(first_name_success && last_name_success && score_success) {
append_records_name(ifp, last_name_input);
append_records_name(ifp, first_name_input);
append_records_score(ifp, score);
}
}
if(c > 0) {
if(c > (int)num_records)
fprintf(stderr, "No records to display \n");
else
print_record(ifp, c);
}
if(c < 0) {
c = c + (-2 * c);
if(c > (int)num_records)
fprintf(stderr, "No records to display \n");
else
for(i = c; i <= num_records; i++)
print_record(ifp, i);
}
}
}
}
/*
- The driver class for this program.
*/
int main(int argc, char* argv[]) {
FILE *ifp;
if(argc != 2) {
fprintf(stderr, "usage: %s file \n", argv[0]);
return 1;
}
if((ifp = fopen(argv[1], "ab+")) == 0) {
perror("fopen");
return 2;
}
program_structure(ifp);
if(fclose(ifp) != 0) {
perror("fclose");
return 3;
}
return 1;
}