added file error handling

This commit is contained in:
Win 2024-09-19 13:36:17 +07:00
parent a6f62cf778
commit a90038c80e
6 changed files with 446 additions and 3 deletions

BIN
#vendorInfo# Executable file

Binary file not shown.

437
#vendorInfo.c# Normal file
View File

@ -0,0 +1,437 @@
/*
* vendorInfo.c
*
* SEN-102 Intro to Programming - Pre-Assessment
* Program that simulates a market containing vendors.
*
* Created by Win (Thanawin Pattanaphol), 28th August 2024
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_VENDORS 20
#define MAX_FILENAME_LENGTH 4096
/* STRUCTURES */
typedef struct vendor
{
char vendor_name[20];
char merchandise[15];
int inventory_count;
int item_price_baht;
int revenue;
int duplicate;
} vendor;
// Return type for search function
typedef struct search_r
{
int status;
int item_id;
} search_r;
// Return type for purchase function
typedef struct purchase_r
{
int status;
char vendor_name[20];
int price_owe_baht;
} purchase_r;
vendor vendors[MAX_VENDORS];
/* FUNCTION DECLARATION */
int getstr(char str[], size_t n);
char *strnlower(char *s, size_t n);
search_r search
(
char query[],
vendor vendors[MAX_VENDORS],
int total_vendors
);
purchase_r purchase
(
int item_id,
int amount,
vendor vendors[MAX_VENDORS]
);
int check_vendors(vendor vendors[MAX_VENDORS], int total_vendors);
int main()
{
char file_name[MAX_FILENAME_LENGTH];
printf("Enter name of input file: ");
getstr(file_name, MAX_FILENAME_LENGTH);
FILE *fp;
if ((fp = fopen(file_name, "r")) == NULL)
{
printf("%s cannot be opened.\n", file_name);
exit(EXIT_FAILURE);
}
// Calculate the file size
fseek(fp, 0, SEEK_END);
unsigned long file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
// Dynamically allocate buffer for file content
char *file_buffer = (char *) malloc(file_size);
int index = 0;
// Reading the file with fgets and formatting them using strtok
while ((fgets(file_buffer, 50, fp) != NULL) && (index <= MAX_VENDORS - 1))
{
char *token = strtok(file_buffer, " ");
strncpy(vendors[index].vendor_name, token, strlen(token) + 1);
token = strtok(NULL, " ");
strncpy(vendors[index].merchandise, token, strlen(token) + 1);
token = strtok(NULL, " ");
vendors[index].inventory_count = atoi(token);
token = strtok(NULL, " ");
vendors[index].item_price_baht = atoi(token);
index++;
}
if (ferror(fp))
{
printf("");
}
int total_vendors = index;
printf("\n>>> Read %d vendors from file %s\n", total_vendors, file_name);
// Print out each vendor's info - excluding duplicates.
for (int i = 0; i <= (total_vendors - 1); i++)
{
/*
This is similar to a linear search algorithm
i = the current item
j = the item next to i
i is being compared to j:
- if i == j then mark both i and j as duplicates
- if not, move on to the next two items
*/
for (int j = i + 1; j < total_vendors; j++)
{
if ((strcmp(vendors[i].merchandise, vendors[j].merchandise)) == 0)
{
vendors[j].duplicate = 1;
}
if ((strcmp(vendors[i].vendor_name, vendors[j].vendor_name)) == 0)
{
vendors[j].duplicate = 1;
}
}
if (vendors[i].duplicate == 0)
{
char vendor_info[200];
sprintf(vendor_info, "%s sells %s for %d each",
vendors[i].vendor_name,
vendors[i].merchandise,
vendors[i].item_price_baht
);
char vendor_stock[50];
sprintf(vendor_stock, "Inventory %d items",
vendors[i].inventory_count
);
printf("%-50s %s\n", vendor_info, vendor_stock);
}
else
{
printf("\e[31m%s\e[m\n", "Duplicate record detected!");
}
}
printf("\n");
while (1)
{
if(check_vendors(vendors, total_vendors) == 0)
{
break;
};
char user_query[100];
printf("What do you want to buy? (DONE to end) ");
getstr(user_query, 100);
if (
(strcmp(user_query, "DONE") == 0) ||
(strcmp(user_query, "done") == 0)
)
{
break;
}
if (strcmp(user_query, "") == 0)
{
printf("Please enter an item name\n");
}
else
{
// convert string to lowercase - each character one by one
int user_query_length = strlen(user_query);
strnlower(user_query, user_query_length);
struct search_r item = search(user_query, vendors, total_vendors);
if(item.status == 0)
{
char input[10];
printf("How many do you want to buy? ");
getstr(input, 10);
// If a character of a string was sent, the return value would always be 0
// If a negative number was sent, the return value will always be negative.
if(atoi(input) > 0)
{
int item_amount = atoi(input);
purchase_r response = purchase(item.item_id, item_amount, vendors);
if (response.status == 0)
{
printf("You owe %s a total of %d baht.\n",
response.vendor_name,
response.price_owe_baht
);
}
else
{
printf("\e[31m%s -- %s %s\e[m\n",
"Sorry",
response.vendor_name,
"does not have enough items available"
);
}
}
else
{
printf("\e[31m%s\e[m\n",
"You must enter a positive whole number for the number of items"
);
}
}
else if (item.status == 2)
{
printf("\e[31m%s\e[m\n",
"This item has duplicate records, please choose another item"
);
}
else
{
printf("\e[31m%s %s\e[m\n",
"No vendor in this market sells",
user_query
);
}
}
}
printf("\n>>> End of day details\n");
// Print out remaining inventory
for (int i = 0; i <= (total_vendors - 1); i++)
{
if (vendors[i].duplicate == 0)
{
char vendor_info[200];
sprintf(vendor_info, "%s made %d baht today",
vendors[i].vendor_name,
vendors[i].revenue
);
char vendor_stock[50];
sprintf(vendor_stock, "Remaining inventory %d items",
vendors[i].inventory_count
);
printf("%-50s %s\n", vendor_info, vendor_stock);
}
}
fclose(fp);
free(file_buffer);
return 0;
};
/*
getstr: Custom read input function
Parameters:
- str = string itself
- n = max amount of characters that the function is able to read into buffer
Reads one character at a time into buffer and adds a null terminator when finish reading
*/
int getstr(char str[], size_t n)
{
int ch, i = 0;
while ((ch = getchar()) != '\n')
{
if (i < (int)n)
{
str[i++] = ch;
}
}
str[i] = '\0';
return i;
};
/*
strnlower: Convert string to lowercase
Parameters:
- s: String
- n: Length of string
Return values:
- (char *): Lowercased version of the string.
*/
char *strnlower(char *s, size_t n)
{
for (int i = 0; i < (int) n; i++)
{
s[i] = tolower(s[i]);
};
}
/*
Search function
Parameters:
- (string) query: search query
- (vendor) vendors: the vendor table
- (int) total_vendors: the amount of vendors
Return values:
(search_r) response:
- status: 0 (Found item)
- status: 1 (No results)
- status: 2 (Found duplicate item)
*/
search_r search(char query[], vendor vendors[MAX_VENDORS], int total_vendors)
{
int i;
for (i = 0; i < total_vendors; i++)
{
// First, check if duplicate
if (strcmp(query, vendors[i].merchandise) == 0)
{
if (vendors[i].duplicate == 0)
{
search_r response;
response.status = 0;
response.item_id = i;
return (response);
break;
}
else
{
search_r response;
response.status = 2;
return (response);
}
}
};
if (i == total_vendors)
{
search_r response;
response.status = 1;
response.item_id = 0;
return (response);
}
};
/*
purchase: Purchase function
Parameters:
- item_id: The item id that the user is purchasing
- amount: How many items that the user is purchasing
- vendors: vendor table
Return values:
(purchase_r) response:
- status: 0 (Purchase successful)
- status: 1 (Vendor does not have enough items)
*/
purchase_r purchase(int item_id, int amount, vendor vendors[MAX_VENDORS])
{
if(amount <= vendors[item_id].inventory_count)
{
// Decrease vendor inventory
vendors[item_id].inventory_count = vendors[item_id].inventory_count - amount;
purchase_r response;
response.status = 0;
strcpy(response.vendor_name, vendors[item_id].vendor_name);
response.price_owe_baht = vendors[item_id].item_price_baht * amount;
vendors[item_id].revenue = vendors[item_id].item_price_baht * amount;
return response;
}
else
{
purchase_r response;
response.status = 1;
strcpy(response.vendor_name, vendors[item_id].vendor_name);
return response;
}
};
/*
check_vendors: Custom function to check if all vendors are empty.
Parameters:
- vendors[MAX_VENDORS]: (vendor) All of the vendors.
- total_vendors: (integer) Total vendors in market.
Return values:
- (int) 0: All vendors are empty.
- (int) 1: There are still items left.
*/
int check_vendors(vendor vendors[MAX_VENDORS], int total_vendors)
{
int i;
for (i = 0; i < total_vendors; i++)
{
// Condition: Vendors that are not empty (Check if not marked as duplicates)
if (vendors[i].inventory_count != 0 && vendors[i].duplicate == 0)
{
return 1;
}
}
if (i == total_vendors)
{
return 0;
}
};

View File

@ -8,6 +8,7 @@ Oat watches 9 120
Lila jackets 7 380
Mary toys 17 39
Kitty dishes 11 67
Win books 30 165
Pat comics 22 18
Jay shoes 22 300
Mark dvds 10 200

Binary file not shown.

View File

@ -72,7 +72,7 @@ int main()
FILE *fp;
if ((fp = fopen(file_name, "r")) == NULL)
{
printf("%s cannot be opened.\n", file_name);
perror("Error opening file");
exit(EXIT_FAILURE);
}
@ -103,6 +103,12 @@ int main()
index++;
}
// Error handling
if (ferror(fp))
{
printf("An error occured while reading the file.\n");
}
int total_vendors = index;
printf("\n>>> Read %d vendors from file %s\n", total_vendors, file_name);
@ -122,13 +128,11 @@ int main()
{
if ((strcmp(vendors[i].merchandise, vendors[j].merchandise)) == 0)
{
vendors[i].duplicate = 1;
vendors[j].duplicate = 1;
}
if ((strcmp(vendors[i].vendor_name, vendors[j].vendor_name)) == 0)
{
vendors[i].duplicate = 1;
vendors[j].duplicate = 1;
}
}

View File

@ -2,3 +2,4 @@ Win phone 1 50
Peter books 1 70
Amy teeshirts 5 100
Deez computers 5 80
kjflkfdl lkdfjlkslkfslklk sdfdsjf dslkfjdslfkjs