119 lines
3.2 KiB
C
119 lines
3.2 KiB
C
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
typedef struct {
|
|
double first, second;
|
|
char op;
|
|
} CalcStr;
|
|
|
|
CalcStr parse_input(int n, char *argv[]);
|
|
double parse_str_to_int(const char *str);
|
|
double calculate(CalcStr calc);
|
|
char* manipulate_str(double input);
|
|
|
|
int main(const int argc, char *argv[]) {
|
|
const double res = calculate(parse_input(argc, argv));
|
|
|
|
char* final_string = manipulate_str(res);
|
|
printf("%s %s %s = %s\n", argv[1], argv[2], argv[3], final_string);
|
|
|
|
free(final_string);
|
|
return 0;
|
|
}
|
|
|
|
CalcStr parse_input(const int n, char *argv[]) {
|
|
if (n < 4) {
|
|
fprintf(stderr, "Insuficient arguments (3 are required), exiting...\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
const CalcStr calc = {parse_str_to_int(argv[1]), parse_str_to_int(argv[3]), *argv[2]};
|
|
return calc;
|
|
}
|
|
|
|
double parse_str_to_int(const char *str) {
|
|
char *endptr;
|
|
errno = 0;
|
|
const double num = strtof(str, &endptr);
|
|
|
|
if (errno == ERANGE || num < INT_MIN || num > INT_MAX) {
|
|
fprintf(stderr, "Input '%s' out of bounds\n", str);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
if (endptr == str) {
|
|
fprintf(stderr, "No digits were found\n");
|
|
} else if (*endptr != '\0') {
|
|
fprintf(stderr, "Invalid character '%c' in input '%s'\n", *endptr, str);
|
|
} else {
|
|
return num;
|
|
}
|
|
|
|
// if parse fails then quit
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
double calculate(const CalcStr calc) {
|
|
switch (calc.op) {
|
|
case '+':
|
|
return calc.first + calc.second;
|
|
case '-':
|
|
return calc.first - calc.second;
|
|
case 'x':
|
|
return calc.first * calc.second;
|
|
case '/':
|
|
return calc.first / calc.second;
|
|
case '%':
|
|
return (int)calc.first % (int)calc.second;
|
|
case '^':
|
|
double r = 1;
|
|
for (int i = (int)calc.second; i > 0; i--) {
|
|
r *= calc.first;
|
|
}
|
|
|
|
return r;
|
|
default:
|
|
fprintf(stderr, "Invalid operand type\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
char* manipulate_str(const double input) {
|
|
const int digit = abs((int)input) == 0 ? 1 : abs((int)input);
|
|
const int str_basesize = (int)log10(digit) + 16 + 1;
|
|
char *str = malloc(str_basesize * sizeof(char));
|
|
if (str == nullptr) {
|
|
printf("Failed to allocate the memory\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
memset(str, 0, str_basesize);
|
|
snprintf(str, str_basesize, "%f", input);
|
|
|
|
char *ptr_to_zero = nullptr;
|
|
|
|
// if it is check if the zeroes are trailing
|
|
for (char *i = str; *i != '\0'; i++) {
|
|
/* we will only show the last location where zeroes start
|
|
if ptr has been reset and we have stumbled upon a zero */
|
|
if (*i == '0' && ptr_to_zero == nullptr) {
|
|
ptr_to_zero = i;
|
|
// reset the pointer if the following digit is no longer zero
|
|
} else if (*i != '0') {
|
|
ptr_to_zero = nullptr;
|
|
}
|
|
}
|
|
|
|
// check if floating point is necessary at all
|
|
if (*(ptr_to_zero - 1) == '.') {
|
|
ptr_to_zero--;
|
|
}
|
|
|
|
// clean the excess characters: ptr_to_zero is now the final char of the string
|
|
*ptr_to_zero = '\0';
|
|
|
|
return str;
|
|
} |