Skip to content

Instantly share code, notes, and snippets.

@easyaspi314
Created April 8, 2019 21:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save easyaspi314/cdff28aeaed8fae55630f1085ad2ffdd to your computer and use it in GitHub Desktop.
Save easyaspi314/cdff28aeaed8fae55630f1085ad2ffdd to your computer and use it in GitHub Desktop.
Faversaver project in C
#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