#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_INT 100
typedef enum _result { ok, err_invalid_size, err_is_null } result;
const char *usage_msg =
"Error wrong number of arguments.\n"
"Usage: ./min_list <num1> <num2> ...\n"
" where <num1>, <num2>, ... must be valid integers.\n";
// Copies the value of the smallest value in the tab array in the min variable.
// Returns the pointer to a newly allocated value of the minimum value of the
// array if everything went fine. Returns NULL otherwise
int *list_find_min(int32_t *tab, int size);
// Prints all the element in the tab array.
// Returns err_invalid_size if size <= 0
// Returns err_is_null if tab is NULL
// Returns ok if everything went fine
result list_print(int32_t *tab, int size);
// Exits if the error code shows invalidity
void error_handling(result error_code, int32_t **tab);
// Parses a string to an integer.
// Returns a pointer to newly allocated data.
// Returns NULL if conversion failed.
int *parse_int32(char *arg_to_transform);
// Reads the command line inputs and stores them
// in a newly allocated array.
// Returns the array with the parsed numbers or NULL if allocation failed or an
// invalid number was parsed.
int *read_input(int size, char *char_num[]) {
int32_t *tab = malloc(size * sizeof(*tab));
if (NULL == tab) {
fprintf(stderr, "Memory allocation failed\n");
return NULL;
}
for (int i = 0; i < size; ++i) {
int *num = parse_int32(char_num[i]);
if (NULL == num) {
free(tab);
fprintf(stderr, "Tried to parse %s which is not a valid integer.\n",
char_num[i]);
return NULL;
}
tab[i] = *num;
free(num);
}
return tab;
}
int main(int argc, char *argv[]) {
if (argc == 1) {
fprintf(stderr, "%s", usage_msg);
return EXIT_FAILURE;
}
int size = argc - 1;
int32_t *tab = read_input(size, &argv[1]);
if (NULL == tab) {
fprintf(stderr, "Failure during argument parsing.\n");
return EXIT_FAILURE;
}
printf("Among the numbers in the list:\n");
error_handling(list_print(tab, size), &tab);
int *min = list_find_min(tab, size);
if (NULL == min) {
fprintf(stderr, "Could not find the minimum of the array.\n");
free(tab);
tab = NULL;
return EXIT_FAILURE;
}
printf("The value of the minimum of the numbers is: %d\n", *min);
free(min);
free(tab);
tab = NULL;
return EXIT_SUCCESS;
}
int min_i32(int32_t lhs, int32_t rhs) {
if (lhs < rhs) {
return lhs;
} else {
return rhs;
}
}
// Checks if size is valid and tab is not NULL
result list_is_valid(int32_t *tab, int size) {
if (size <= 0) {
return err_invalid_size;
}
if (NULL == tab) {
return err_is_null;
}
return ok;
}
result list_print(int32_t *tab, int size) {
result code = list_is_valid(tab, size);
if (code != ok) {
return code;
}
for (int i = 0; i < size; ++i) {
printf("%d ", tab[i]);
}
printf("\n");
return code;
}
int32_t *list_find_min(int32_t *tab, int size) {
result code = list_is_valid(tab, size);
if (code != ok) {
return NULL;
}
int32_t *min = malloc(sizeof(*min));
*min = tab[0];
for (int i = 1; i < size; ++i) {
*min = min_i32(*min, tab[i]);
}
return min;
}
void error_handling(result error_code, int32_t **tab) {
switch (error_code) {
case err_invalid_size:
fprintf(stderr, "Return value, %d. Size is <= 0.\n", error_code);
free(*tab);
*tab = NULL;
exit(EXIT_FAILURE);
break;
case err_is_null:
fprintf(stderr, "Tab is NULL.\n");
free(*tab);
*tab = NULL;
exit(EXIT_FAILURE);
break;
case ok:
break;
}
}
int32_t *parse_int32(char *arg_to_transform) {
if (strlen(arg_to_transform) == 0) {
return NULL; // empty string to parse
}
char *remaining;
errno = 0; // errno == 0 (defined in errno.h) means everything went fine
long arg = strtol(arg_to_transform, &remaining,
10); // number is parsed in base 10
if (*remaining != '\0' || errno != 0) {
return NULL; // Empty string parsed or an error occurred
}
if (arg < INT_MIN || arg > INT_MAX) {
return NULL; // Not within the limits of an int
}
int32_t *num = malloc(sizeof(*num));
*num = (int32_t)arg;
return num;
}