added file error handling
This commit is contained in:
parent
a6f62cf778
commit
a90038c80e
Binary file not shown.
|
@ -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;
|
||||||
|
}
|
||||||
|
};
|
|
@ -8,6 +8,7 @@ Oat watches 9 120
|
||||||
Lila jackets 7 380
|
Lila jackets 7 380
|
||||||
Mary toys 17 39
|
Mary toys 17 39
|
||||||
Kitty dishes 11 67
|
Kitty dishes 11 67
|
||||||
|
Win books 30 165
|
||||||
Pat comics 22 18
|
Pat comics 22 18
|
||||||
Jay shoes 22 300
|
Jay shoes 22 300
|
||||||
Mark dvds 10 200
|
Mark dvds 10 200
|
||||||
|
|
BIN
vendorInfo
BIN
vendorInfo
Binary file not shown.
10
vendorInfo.c
10
vendorInfo.c
|
@ -72,7 +72,7 @@ int main()
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
if ((fp = fopen(file_name, "r")) == NULL)
|
if ((fp = fopen(file_name, "r")) == NULL)
|
||||||
{
|
{
|
||||||
printf("%s cannot be opened.\n", file_name);
|
perror("Error opening file");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,6 +103,12 @@ int main()
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error handling
|
||||||
|
if (ferror(fp))
|
||||||
|
{
|
||||||
|
printf("An error occured while reading the file.\n");
|
||||||
|
}
|
||||||
|
|
||||||
int total_vendors = index;
|
int total_vendors = index;
|
||||||
printf("\n>>> Read %d vendors from file %s\n", total_vendors, file_name);
|
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)
|
if ((strcmp(vendors[i].merchandise, vendors[j].merchandise)) == 0)
|
||||||
{
|
{
|
||||||
vendors[i].duplicate = 1;
|
|
||||||
vendors[j].duplicate = 1;
|
vendors[j].duplicate = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((strcmp(vendors[i].vendor_name, vendors[j].vendor_name)) == 0)
|
if ((strcmp(vendors[i].vendor_name, vendors[j].vendor_name)) == 0)
|
||||||
{
|
{
|
||||||
vendors[i].duplicate = 1;
|
|
||||||
vendors[j].duplicate = 1;
|
vendors[j].duplicate = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,3 +2,4 @@ Win phone 1 50
|
||||||
Peter books 1 70
|
Peter books 1 70
|
||||||
Amy teeshirts 5 100
|
Amy teeshirts 5 100
|
||||||
Deez computers 5 80
|
Deez computers 5 80
|
||||||
|
kjflkfdl lkdfjlkslkfslklk sdfdsjf dslkfjdslfkjs
|
||||||
|
|
Loading…
Reference in New Issue