Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXCHARS 40
#define MAXBOOKS 20
struct book {
int flag;
char title[MAXCHARS];
char author[MAXCHARS];
float value;
};
int read_to_struct(struct book * myBooks, int booksize, int count, FILE * pbooks);
char menu(void);
int add_books(struct book * myBooks, int filecount, int booksize, FILE * pbooks);
void delete_books(struct book * myBooks, int filecount, int booksize, FILE * pbooks);
void edit_books(struct book * myBooks, int filecount, int booksize, FILE * pbooks);
int show_books(struct book * myBooks, int init);
void write_to_file(struct book * myBooks, int filecount, int booksize, int count, FILE * pbooks);
int main(void)
{
struct book myBooks[MAXBOOKS] = {0, "", "", (float) 0.0}; // making sure all records are invisible until used
int count = 0;
int filecount;
FILE * pbooks;
int booksize = sizeof(struct book);
char ch;
int init = 1; // this is to set flag for show_books at beginning of program
if ((pbooks = fopen("books.dat", "r+b")) == NULL)
{
fputs("Can't open books.dat\n", stderr);
exit(EXIT_FAILURE);
}
rewind(pbooks);
filecount = count = read_to_struct(myBooks, booksize, count, pbooks); // 'filecount = count' two birds, one stone
init = show_books(myBooks, init);
init = 0; // this is to get rid of special message after first display of books
if (count >= MAXBOOKS)
{
puts("\nThe books.dat file is full.");
puts("You must overwrite an existing record.\n");
}
while ((ch = menu()) != 'q')
{
switch (ch)
{
case 'a' :
count = add_books(myBooks, filecount, booksize, pbooks); // count must be returned for proper show_books() display
filecount += count;
break;
case 'd' :
delete_books(myBooks, filecount, booksize, pbooks);
break;
case 'e' :
edit_books(myBooks, filecount, booksize, pbooks);
break;
case 's' :
init = show_books(myBooks, init);
break;
default :
puts("That's not A, D, E, S or Q! Try again");
}
}
write_to_file(myBooks, filecount, booksize, count, pbooks);
fclose(pbooks);
puts("\nGoodbye!\n");
return 0;
}
/* ################################################## END OF MAIN ####################################### */
// ############################################## INITIAL READ TO STRUCTURES
int read_to_struct(struct book * myBooks, int booksize, int count, FILE * pbooks)
{
while (count < MAXBOOKS && fread(&myBooks[count], booksize, 1, pbooks) == 1) // for reading file records into structure 'myBooks'
{
if (count == 0)
{
puts("Current contents of books.dat:\n");
}
if (myBooks[count].flag == 0)
myBooks[count].flag = 0;
if (myBooks[count].flag == 1) // '2' is flag for 'deleted' - '0' is assigned by default at beginning
myBooks[count].flag = 1;
if (myBooks[count].flag == 2)
myBooks[count].flag = 2;
count++;
}
return count;
}
// ############################################## MENU
char menu(void)
{
char ch;
puts("\n[A]dd a record");
puts("[D]elete a record");
puts("[E]dit a record");
puts("[S]how all records\n");
printf("Make a choice or [Q] to quit:");
ch = getchar();
ch = tolower(ch);
return ch;
}
// ############################################## ADD BOOKS
int add_books(struct book * myBooks, int count, int booksize, FILE * pbooks)
{
char temp[MAXCHARS];
while (getchar() != '\n') // clears out input line from menu
continue;
while (myBooks[count].flag == 1) // this loop bypasses all undeleted records
{
for (count = 0; myBooks[count].flag == 1; count++)
;
}
puts("Please enter book title.");
fgets(temp, sizeof(myBooks->title), stdin);
temp[strlen(temp)-1]='\0'; // copies over the '\n' with an additional null character before end of string
strcpy(myBooks[count].title, temp);
if (strlen(temp) > 1)
myBooks[count].flag = 1; // without this, show_books will only display new entries after program restart!
puts("Please enter author name.");
fgets(temp, sizeof(myBooks->author), stdin);
temp[strlen(temp)-1]='\0';
strcpy(myBooks[count].author, temp);
puts("Now enter the price, or 'q' to quit.");
scanf("%f", &myBooks[count].value);
count++;
while (getchar() != '\n') // clears input line
continue;
return count;
}
// ############################################## DELETE BOOKS
void delete_books(struct book * myBooks, int filecount, int booksize, FILE * pbooks)
{
char ch;
int count = 0;
while (getchar() != '\n') // clears input line from menu selection
continue;
while (count < filecount)
{
if (myBooks[count].flag == 0 || myBooks[count].flag == 2) // keeps user from seeing unused or deleted records
count++; // and increments count past them
else
{
printf("\n%s by %s: $%.2f\n", myBooks[count].title, myBooks[count].author, myBooks[count].value);
printf("Would you like to delete this record? 'Y' to delete, [Enter] to skip.\n");
}
if ((ch = getchar()) == 'Y' || ch == 'y')
{
myBooks[count].flag = 2; // assigns '2' to flag if record is 'deleted' by user
while (getchar() != '\n')
continue;
}
count++;
}
}
// ############################################## EDIT BOOKS
void edit_books(struct book * myBooks, int filecount, int booksize, FILE * pbooks)
{
char temp[MAXCHARS];
char ch;
int count = 0;
while (getchar() != '\n') // clears input line from menu selection
continue;
while (count < filecount)
{
if (myBooks[count].flag == 0 || myBooks[count].flag == 2) // this prevents overwriting undeleted records
;
else
{
printf("\n%s by %s: $%.2f\n", myBooks[count].title, myBooks[count].author, myBooks[count].value);
printf("Would you like to edit this record? 'Y' to edit, [Enter] to skip.\n");
}
if ((ch = getchar()) == 'Y' || ch == 'y')
{
puts("Please make changes to book title.");
fgets(temp, sizeof(myBooks->title), stdin);
temp[strlen(temp)-1]='\0'; // copies over the '\n' with an additional null character before end of string
strcpy(myBooks[count].title, temp);
puts("Please make changes to author.");
fgets(temp, sizeof(myBooks->author), stdin);
temp[strlen(temp)-1]='\0';
strcpy(myBooks[count].author, temp);
puts("Now enter the price, or 'q' to quit.");
scanf("%f", &myBooks[count].value);
}
count++;
}
}
// ############################################## SHOW BOOKS
int show_books(struct book * myBooks, int init)
{
int index;
printf("\n");
for (index = 0; index < MAXBOOKS; index++)
{
if (myBooks[index].flag == 0 || myBooks[index].flag == 2) // makes deleted and unused records invisible
;
else
printf("%s by %s: $%.2f\n", myBooks[index].title, myBooks[index].author, myBooks[index].value);
}
if (init == 1)
puts("\nPress [Enter] to continue.");
while (getchar() != '\n') // clears input line
continue;
return init;
}
// ############################################## WRITE TO FILE
void write_to_file(struct book * myBooks, int filecount, int booksize, int count, FILE * pbooks)
{
rewind(pbooks); // VITAL to prevent fwrite() from writing the contents of pbooks twice!!!
fwrite(&myBooks[0], booksize, count, pbooks);
}