First off, the overall structure you have is somewhat decent. You need to breakdown the operations in AddBook a bit more though. You have a couple of repeated patterns. Look how much easier the code is starting to look if you pull out the input patterns:
Code:
void get_string(const char * prompt, char * buf, size_t size)
{
printf("%s", prompt);
if (!fgets(buf, size, stdin)) {
perror("get_string");
*buf = 0;
}
}
/* Accept int within a range */
int get_int(const char * prompt, int rstart, int rend)
{
int again, value;
do {
again = 0;
printf("%s", prompt);
if (!scanf(" %d", value) || value < rstart || (rend > 0 && value > rend)) {
printf("Error: please enter a valid value\n");
again = 1;
}
} while (again);
return value;
}
int AddBooks(char *filename)
{
FILE *fp;
book newbook;
struct tm date;
system("cls");
fp = fopen(filename, "wb");
if (!fp) {
printf("Error reading database file!\n");
return -1;
}
get_string("Please type in the book's title:\n",
newbook.title,
sizeof newbook.title
);
get_string("Please type in the reader's name:\n",
newbook.reader_name,
sizeof newbook.reader_name
);
int d, m, y;
int days_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int minyear = 1900;
printf("\nPlease enter the date of rent:\n\n");
y = get_int("Year (yyyy): ", minyear, -1);
/* Calculate leapyear */
if ((y % 4) == 0 && y % 100 != 0 || y % 400 == 0)
days_month[2] = 29;
else
days_month[2] = 28;
m = get_int("Month (mm): ", 1, 12);
d = get_int("Day (dd): ", 1, days_months[m]);
date.tm_mday = d;
date.tm_mon = m - 1;
date.tm_year = y - 1900;
newbook.unix_date = mktime(&date);
fwrite(&newbook, sizeof(book), 1, fp);
system("cls");
printf("Item successfully added to the registry.\n\n");
fclose(fp);
ReturnToMenu();
}
Now some issues. Number one you do not want to write out your data directly to file in raw binary format as you are doing. For one, you said it was a linked list right? So you need to load the whole file into memory, re-substantiate all the links to form the list (from the structures stored, presumably in sequential order..) then add the item to the list, then write out the whole list to the file again. That would be the only way to actually maintain the database structure in memory and in a file.
For that reason you probably would only want to read/write the list to file once each per run of your program, not every single time you do every operation. So you may want to think about that a bit.
Beyond all that, writing the data structure raw with an fwrite() call you will run into issues if you copy those files to another computer, or try to send them over the network to someone else etc.. or even use them with another version of your program, due to byte ordering and structure padding (which has been explained billions of times, you need to read the FAQ).
Finally, yes the problem of your scanf() calls being consumed "magically" as it would seem, is in fact because they are consuming the "enter" key as you put it. This is again probably the most commonly asked question on the forum and likely why you haven't gotten an answer. You need to read the FAQ. In general you can solve this problem by placing a space in front of your scanf() call as I have done in the code above. This consumes the whitespace left in the buffer prior to trying to read another integer.