vendor-info/vendorInfo.c

439 lines
8.8 KiB
C
Raw Normal View History

2024-08-28 19:00:25 +07:00
/*
* vendorInfo.c
2024-09-05 10:13:53 +07:00
*
* SEN-102 Intro to Programming - Pre-Assessment
* Program that simulates a market containing vendors.
2024-09-05 10:13:53 +07:00
*
* Created by Win (Thanawin Pattanaphol), 28th August 2024
*/
2024-08-28 19:00:25 +07:00
#include <stdio.h>
#include <stdlib.h>
2024-08-29 11:31:21 +07:00
#include <string.h>
#include <ctype.h>
2024-08-28 19:00:25 +07:00
#define MAX_VENDORS 20
#define MAX_FILENAME_LENGTH 4096
2024-09-05 12:49:56 +07:00
/* STRUCTURES */
typedef struct vendor
2024-08-29 10:57:19 +07:00
{
2024-08-28 19:00:25 +07:00
char vendor_name[20];
char merchandise[15];
int inventory_count;
int item_price_baht;
int revenue;
int duplicate;
} vendor;
2024-08-28 19:00:25 +07:00
// Return type for search function
typedef struct search_r
2024-09-05 12:49:56 +07:00
{
int status;
int item_id;
} search_r;
2024-09-05 12:49:56 +07:00
// Return type for purchase function
typedef struct purchase_r
2024-09-05 10:13:53 +07:00
{
int status;
char vendor_name[20];
int price_owe_baht;
} purchase_r;
vendor vendors[MAX_VENDORS];
2024-09-05 10:13:53 +07:00
2024-09-05 12:49:56 +07:00
/* FUNCTION DECLARATION */
int getstr(char str[], size_t n);
2024-09-06 08:52:53 +07:00
char *strnlower(char *s, size_t n);
2024-09-05 10:13:53 +07:00
search_r search
2024-09-05 12:49:56 +07:00
(
char query[],
vendor vendors[MAX_VENDORS],
2024-09-05 12:49:56 +07:00
int total_vendors
);
2024-09-05 10:13:53 +07:00
purchase_r purchase
2024-09-05 12:49:56 +07:00
(
int item_id,
int amount,
vendor vendors[MAX_VENDORS]
2024-09-05 12:49:56 +07:00
);
int check_vendors(vendor vendors[MAX_VENDORS], int total_vendors);
int main()
{
2024-08-28 19:00:25 +07:00
char file_name[MAX_FILENAME_LENGTH];
2024-08-29 15:30:23 +07:00
printf("Enter name of input file: ");
getstr(file_name, MAX_FILENAME_LENGTH);
2024-08-28 19:00:25 +07:00
FILE *fp;
2024-08-29 10:57:19 +07:00
if ((fp = fopen(file_name, "r")) == NULL)
{
2024-09-19 13:36:17 +07:00
perror("Error opening file");
2024-08-28 19:00:25 +07:00
exit(EXIT_FAILURE);
}
// Calculate the file size
2024-08-29 10:57:19 +07:00
fseek(fp, 0, SEEK_END);
unsigned long file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);
// Dynamically allocate buffer for file content
2024-08-29 10:57:19 +07:00
char *file_buffer = (char *) malloc(file_size);
2024-08-29 11:31:21 +07:00
int index = 0;
2024-08-29 10:57:19 +07:00
// Reading the file with fgets and formatting them using strtok
2024-09-07 16:32:42 +07:00
while ((fgets(file_buffer, 50, fp) != NULL) && (index <= MAX_VENDORS - 1))
2024-08-29 11:31:21 +07:00
{
char *token = strtok(file_buffer, " ");
2024-08-29 15:30:23 +07:00
strncpy(vendors[index].vendor_name, token, strlen(token) + 1);
2024-08-29 11:31:21 +07:00
token = strtok(NULL, " ");
2024-08-29 15:30:23 +07:00
strncpy(vendors[index].merchandise, token, strlen(token) + 1);
2024-08-29 11:31:21 +07:00
token = strtok(NULL, " ");
vendors[index].inventory_count = atoi(token);
token = strtok(NULL, " ");
vendors[index].item_price_baht = atoi(token);
2024-08-29 15:30:23 +07:00
index++;
2024-08-29 11:31:21 +07:00
}
2024-09-19 13:36:17 +07:00
// Error handling
if (ferror(fp))
{
printf("An error occured while reading the file.\n");
}
2024-09-07 16:32:42 +07:00
int total_vendors = index;
2024-08-29 15:30:23 +07:00
printf("\n>>> Read %d vendors from file %s\n", total_vendors, file_name);
2024-08-29 20:04:02 +07:00
// Print out each vendor's info - excluding duplicates.
2024-09-07 16:32:42 +07:00
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
*/
2024-09-07 16:32:42 +07:00
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;
2024-09-07 16:32:42 +07:00
}
}
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!");
}
2024-08-29 15:30:23 +07:00
}
2024-09-03 09:20:56 +07:00
2024-09-07 16:32:42 +07:00
printf("\n");
2024-09-03 09:20:56 +07:00
while (1)
2024-09-01 18:25:50 +07:00
{
if(check_vendors(vendors, total_vendors) == 0)
{
break;
};
2024-09-05 10:13:53 +07:00
char user_query[100];
printf("What do you want to buy? (DONE to end) ");
getstr(user_query, 100);
2024-09-05 10:13:53 +07:00
if (
(strcmp(user_query, "DONE") == 0) ||
(strcmp(user_query, "done") == 0)
)
2024-09-03 09:20:56 +07:00
{
break;
}
if (strcmp(user_query, "") == 0)
2024-09-03 13:00:50 +07:00
{
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)
2024-09-03 13:00:50 +07:00
{
char input[10];
2024-09-05 10:13:53 +07:00
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
2024-09-05 10:13:53 +07:00
{
printf("\e[31m%s\e[m\n",
"You must enter a positive whole number for the number of items"
);
2024-09-05 10:13:53 +07:00
}
2024-09-05 10:13:53 +07:00
}
else if (item.status == 2)
2024-09-03 13:00:50 +07:00
{
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
);
2024-09-03 13:00:50 +07:00
}
}
}
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)
2024-09-03 13:00:50 +07:00
{
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);
2024-09-03 13:00:50 +07:00
}
2024-09-03 09:20:56 +07:00
}
2024-08-29 15:30:23 +07:00
2024-08-28 19:00:25 +07:00
fclose(fp);
2024-08-29 10:57:19 +07:00
free(file_buffer);
2024-08-28 19:00:25 +07:00
return 0;
};
2024-09-01 18:37:50 +07:00
/*
getstr: Custom read input function
Parameters:
- str = string itself
- n = max amount of characters that the function is able to read into buffer
2024-09-01 18:37:50 +07:00
Reads one character at a time into buffer and adds a null terminator when finish reading
2024-09-01 18:37:50 +07:00
*/
int getstr(char str[], size_t n)
2024-08-29 10:57:19 +07:00
{
2024-08-28 19:00:25 +07:00
int ch, i = 0;
2024-08-29 10:57:19 +07:00
while ((ch = getchar()) != '\n')
{
2024-09-06 08:52:53 +07:00
if (i < (int)n)
2024-08-29 10:57:19 +07:00
{
2024-08-28 19:00:25 +07:00
str[i++] = ch;
}
}
str[i] = '\0';
return i;
2024-08-29 15:30:23 +07:00
};
2024-08-29 20:04:02 +07:00
2024-09-06 08:52:53 +07:00
/*
strnlower: Convert string to lowercase
Parameters:
- s: String
- n: Length of string
Return values:
- (char *): Lowercased version of the string.
2024-09-06 08:52:53 +07:00
*/
char *strnlower(char *s, size_t n)
{
for (int i = 0; i < (int) n; i++)
{
s[i] = tolower(s[i]);
};
}
2024-09-01 18:37:50 +07:00
/*
Search function
Parameters:
- (string) query: search query
- (vendor) vendors: the vendor table
- (int) total_vendors: the amount of vendors
2024-09-03 09:20:56 +07:00
Return values:
(search_r) response:
- status: 0 (Found item)
- status: 1 (No results)
- status: 2 (Found duplicate item)
2024-09-01 18:37:50 +07:00
*/
2024-09-05 10:13:53 +07:00
search_r search(char query[], vendor vendors[MAX_VENDORS], int total_vendors)
{
2024-09-01 18:25:50 +07:00
int i;
for (i = 0; i < total_vendors; i++)
{
// First, check if duplicate
2024-09-01 18:25:50 +07:00
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);
}
}
2024-09-01 18:25:50 +07:00
};
if (i == total_vendors)
{
search_r response;
2024-09-05 12:49:56 +07:00
response.status = 1;
response.item_id = 0;
return (response);
2024-09-01 18:25:50 +07:00
}
};
2024-09-01 18:37:50 +07:00
/*
purchase: Purchase function
2024-09-01 18:37:50 +07:00
Parameters:
2024-09-03 09:20:56 +07:00
- item_id: The item id that the user is purchasing
2024-09-01 18:37:50 +07:00
- amount: How many items that the user is purchasing
- vendors: vendor table
2024-09-03 09:20:56 +07:00
Return values:
(purchase_r) response:
- status: 0 (Purchase successful)
- status: 1 (Vendor does not have enough items)
2024-09-01 18:37:50 +07:00
*/
purchase_r purchase(int item_id, int amount, vendor vendors[MAX_VENDORS])
{
2024-09-03 09:20:56 +07:00
if(amount <= vendors[item_id].inventory_count)
{
2024-09-05 10:13:53 +07:00
// Decrease vendor inventory
2024-09-03 09:20:56 +07:00
vendors[item_id].inventory_count = vendors[item_id].inventory_count - amount;
2024-09-05 10:13:53 +07:00
purchase_r response;
2024-09-05 10:13:53 +07:00
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;
2024-09-03 13:00:50 +07:00
return response;
2024-09-03 09:20:56 +07:00
}
else
{
purchase_r response;
2024-09-05 10:13:53 +07:00
response.status = 1;
strcpy(response.vendor_name, vendors[item_id].vendor_name);
2024-09-05 10:13:53 +07:00
return response;
2024-09-03 09:20:56 +07:00
}
};
/*
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;
}
};