Created
April 8, 2019 21:28
-
-
Save easyaspi314/cdff28aeaed8fae55630f1085ad2ffdd to your computer and use it in GitHub Desktop.
Faversaver project in C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Product.h" | |
#include "ErrorState.h" | |
#include "iProduct.h" | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
static const struct iProductVtable Product_vtable; | |
static void setProductName(Product *pro, const char *product_name); | |
void Product_init(Product *pro) | |
{ | |
pro->vtbl = &Product_vtable; | |
} | |
static void condensed(const Product *pro, char *); | |
static double priceAfterTax(const Product *pro); | |
void Product_message(Product *pro, const char *pText) | |
{ | |
free(pro->err); | |
size_t len = strlen(pText) + 1; | |
pro->err = (char *)malloc(len); | |
memcpy(pro->err, pText, len); | |
} | |
bool Product_isClear(const Product *pro) | |
{ | |
return !pro->err; | |
} | |
Product *Product_create(char type, const char *sku, const char *name, const char *unit, double price_bt, int needed, int quantity, bool taxables) | |
{ | |
Product *pro = (Product *)calloc(1, sizeof(Product)); | |
pro->vtbl = &Product_vtable; | |
if (name != NULL && name[0] != '\0') { | |
pro->name = NULL; | |
strncpy(pro->sku, sku, max_length_sku); | |
pro->sku[max_length_sku] = '\0'; | |
setProductName(name); | |
strncpy(pro->unit, unit, max_length_unit); | |
pro->unit[max_length_unit] = '\0'; | |
pro->before_tax = price_bt; | |
pro->quantity = quantity; | |
pro->needed = needed; | |
pro->taxable = taxables; | |
} | |
} | |
void Product_destroy(Product *pro) | |
{ | |
free(pro->name); | |
free(pro->err); | |
free(pro->buffer); | |
} | |
void Product_copy(Product *pro, const Product *other) | |
{ | |
if (prod != other) { | |
strncpy(pro->sku, other->pro->sku, max_length_sku); | |
if (other->pro->name != NULL) { | |
if (strlen(other->pro->name) > max_length_name) { | |
pro->name = (char *)malloc(max_length_name + 1); | |
strncpy(pro->name, other->pro->name, max_length_name); | |
} else { | |
pro->name = (char *)malloc(max_length_name + 1); | |
strncpy(pro->name, other->pro->name, max_length_name); | |
} | |
} else { | |
pro->name = NULL; | |
} | |
strncpy(pro->unit, other->pro->unit, max_length_unit); | |
pro->vtbl = &Product_vtable; | |
pro->quantity = other->pro->quantity; | |
pro->needed = other->pro->needed; | |
pro->before_tax = other->pro->before_tax; | |
pro->taxable = other->pro->taxable; | |
} | |
return *this; | |
} | |
static int add(void *pro_ptr, int cnt) | |
{ | |
Product *pro = (Product *)pro_ptr; | |
if (cnt > 0) { | |
pro->quantity += cnt; | |
} | |
return pro->quantity; | |
} | |
static const char *name(const void *pro_ptr) | |
{ | |
const Product *pro = (const Product *)pro_ptr; | |
return pro->name; | |
} | |
static bool equal(const void *pro_ptr, const char *sku) | |
{ | |
const Product *pro = (const Product *)pro_ptr; | |
return strcmp(pro->sku, sku) == 0; | |
} | |
static bool greater(const void *pro_ptr, const char *sku) | |
{ | |
const Product *pro = (const Product *)pro_ptr; | |
return strcmp(pro->sku, sku) > 0; | |
} | |
// todo: figure out the right name | |
// bool Product::operator> (const iProduct& other) const | |
// { | |
// return strcmp(pro->name, other.name()) > 0; | |
// } | |
static int qtyAvailable(const void *pro_ptr) | |
{ | |
const Product *pro = (const Product *)pro_ptr; | |
return pro->quantity; | |
} | |
static int qtyNeeded(const void *pro_ptr) | |
{ | |
const Product *pro = (const Product *)pro_ptr; | |
return pro->needed; | |
} | |
static double total_cost(const void *pro_ptr) | |
{ | |
const Product *pro = (const Product *)pro_ptr; | |
double temp = 0.0; | |
if (pro->taxable == true) { | |
temp = (pro->before_tax * pro->quantity) * (1 + tax_rate); | |
} else { | |
temp = pro->before_tax * pro->quantity; | |
} | |
return temp; | |
} | |
static bool isEmpty(const void *pro_ptr) | |
{ | |
const Product *pro = (const Product *)pro_ptr; | |
if (pro->name == NULL || pro->name[0] == '\0') | |
return true; | |
else | |
return false; | |
} | |
static void setProductName(Product *pro, const char *product_name) | |
{ | |
free(pro->name); | |
pro->name = (char *)malloc(max_length_name + 1); | |
strncpy(pro->name, product_name, max_length_name); | |
pro->name[max_length_name] = '\0'; | |
} | |
static double priceAfterTax(const Product *pro) | |
{ | |
if (pro->taxable) { | |
return pro->before_tax * (1 + tax_rate); | |
} else { | |
return pro->before_tax; | |
} | |
} | |
static void condensed(const Product *pro, char *cname) | |
{ | |
int length; | |
const int maxlength = 17; | |
for (length = 0; pro->name[length] != '\0'; length++) { | |
if (length < maxlength) { | |
strncpy(cname, pro->name, maxlength); | |
} else { | |
strncpy(cname, pro->name, 13); | |
cname[13] = '.'; | |
cname[14] = '.'; | |
cname[15] = '.'; | |
cname[16] = '\0'; | |
} | |
} | |
} | |
static void product_read(void *pro_ptr, FILE *in, bool interractive) | |
{ | |
Product *pro = (Product *)pro_ptr; | |
ssize_t count; | |
// Only snprintf once | |
static char scanf_string[128][3] = { 0 }; | |
if (scanf_string[0][0] == '\0') { | |
snprintf(scanf_string[0], sizeof(scanf_string[0]), "%%%ds,%[^,],%%%d[^,],%%lf,%[^,],%d,d\n", max_length_sku - 1, max_length_unit - 1); | |
snprintf(scanf_string[1], sizeof(scanf_string[1]), "%%%ds", max_length_sku - 1); | |
snprintf(scanf_string[2], sizeof(scanf_string[2]), "%%%ds", max_length_unit - 1); | |
} | |
if (interractive == false) { | |
if ((count = getline(&pro->buffer, &pro->buffer_size, in)) > 0) { | |
// create a temp buffer for the name string and the taxable string. | |
// malloc full length to be safe. | |
char *temp_name = (char *)malloc(count + 1); | |
char *temp_taxable = (char *)malloc(count + 1); | |
int status = sscanf(pro->buffer, scanf_string[0], | |
pro->sku, | |
temp_name, | |
pro->unit, | |
&pro->before_taxable, | |
temp_taxable, | |
&pro->quantity, | |
&pro->needed); | |
if (status != 0) { | |
Product_message(pro, status < 0 ? "IO error" : "input error"); | |
free(temp_name); | |
free(temp_taxable); | |
return; | |
} | |
setProductName(pro, temp_name); | |
pro->taxable = (tolower(temp_taxable[0]) == 'y' || temp_taxable[0] == '1'); | |
free(temp_name); | |
free(temp_taxable); | |
} | |
} else { | |
int c; | |
// clean stdin | |
while ((c = getchar()) != EOF && c != '\n') | |
; | |
printf("%*s", max_length_label, "Sku: "); | |
count = getline(&pro->buffer, &pro->buffer_size, stdin); | |
if (count < 0) { | |
Product_message("IO error"); | |
return; | |
} | |
if (sscanf(pro->buffer, scanf_string[1], pro->sku) != 1) { | |
Product_message("Invalid SKU"); | |
return: | |
} | |
printf("%*s", max_length_label, "Name: "); | |
count = getline(&pro->buffer, &pro->buffer_size, stdin); | |
if (count < 1) { | |
Product_message(pro, "Invalid name"); | |
return; | |
} | |
pro->buffer[count - 1] = '\0'; // remove the '\n' | |
setProductName(pro, pro->buffer); | |
printf("%*s", max_length_label, "Unit: "); | |
count = getline(&pro->buffer, &pro->buffer_size, stdin); | |
if (count < 0) { | |
Product_message(pro, "IO error"); | |
return; | |
} | |
if (sscanf(pro->buffer, scanf_string[2], pro->unit) != 1) { | |
Product_message(pro, "Invalid input"); | |
return; | |
} | |
printf("%*s", max_length_label, "Taxed? (y/n): "); | |
c = getchar(); | |
if (c != 'y' && c != 'n') { | |
Product_message(pro, "Only (Y)es or (N)o are acceptable!"); | |
return; | |
} | |
while (c != EOF && c != '\n') | |
c = getchar(); | |
printf("%*s", max_length_label, "Price: "); | |
count = getline(&pro->buffer, &pro->buffer_size, stdin); | |
if (count < 0 || sscanf(pro->buffer, "%.2lf", &pro->before_tax) != 1) { | |
Product_message(pro, "Invalid Price Entry!"); | |
return; | |
} | |
printf("%*s", max_length_label, "Quantity on hand: "); | |
count = getline(&pro->buffer, &pro->buffer_size, stdin); | |
if (count < 0 || sscanf(pro->buffer, "%i", &pro->quantity) != 1) { | |
Product_message(pro, "Invalid Quantity Available Entry!"); | |
return; | |
} | |
printf("%*s", max_length_label, "Quantity needed: "); | |
count = getline(&pro->buffer, &pro->buffer_size, stdin); | |
if (count < 0 || sscanf(pro->buffer, "%i", &pro->needed) != 1) { | |
Product_message(pro, "Invalid Quantity Needed Entry!"); | |
return; | |
} | |
} | |
} | |
static void product_write(const void *pro_ptr, FILE *out, int writeMode) | |
{ | |
const Product *pro = (const Product *)pro_ptr; | |
if (!Product_isClear(pro)) { | |
fputs(pro->err.message(), out); | |
} else if (!pro->vtbl->isEmpty(pro)) { | |
const int print_length_sku = max_length_sku; | |
const int print_length_name = 16; | |
const int print_length_unit = 10; | |
const int print_length_price = 7; | |
const int print_length_tax = 3; | |
const int print_length_Quantityonhand = 6; | |
const int print_length_QNeeded = 6; | |
char temp_taxable[4] = { '\0' }; | |
if (pro->taxable) { | |
strncpy(temp_taxable, "yes", 3); | |
temp_taxable[3] = '\0'; | |
} else { | |
strncpy(temp_taxable, "no", 3); | |
temp_taxable[2] = '\0'; | |
} | |
switch (writeMode) { | |
case write_condensed: | |
fprintf(out, "%c,%s,%s,%s,%.2lf,%d,%d,%d", | |
pro->type, | |
pro->sku, | |
pro->name, | |
pro->unit, | |
pro->before_tax, | |
pro->taxable, | |
pro->quantity, | |
pro->needed); | |
break; | |
case write_table: | |
char sName[17]; | |
condensed(pro, sName); | |
fprintf(out, " %*s | %-*s | %-*s | %*.2lf | %*s | %*d | %*d |", | |
print_length_sku, pro->sku, | |
print_length_name, sName, | |
print_length_unit, pro->unit, | |
print_length_price, pro->before_tax, | |
print_length_tax, temp_taxable, | |
print_length_Quantityonhand, pro->quantity, | |
print_length_Qneeded, pro->needeed); | |
break; | |
case write_human: | |
fprintf(out, "%*s%s\n", max_length_label, "Sku: ", pro->sku); | |
fprintf(out, "%*s%s\n", max_length_label, "Name: ", pro->name); | |
fprintf(out, "%*s%.2lf\n", max_length_label, "Price: ", pro->before_tax); | |
fprintf(out, "%*s%.2lf\n", max_length_label, "Priceafter Tax: ", priceAfterTax(pro)); | |
fprintf(out, "%*s%d %s\n", max_length_label, "Quantity Available: ", pro->quantity, pro->unit); | |
fprintf(out, "%*s%d %s\n", max_length_label, "Quantity Needed: ", pro->needed, pro->unit); | |
break; | |
} | |
} | |
} | |
static const iProductVtable Product_Vtable = { | |
&add, | |
&equal, | |
&greater, | |
&qtyAvailable, | |
&qtyNeeded, | |
&total_cost, | |
&isEmpty, | |
&name, | |
&product_read, | |
&product_write | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment