diff --git a/.gitignore b/.gitignore index 36d9195..08d271e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ average +convert_to_ints *.swp diff --git a/Makefile b/Makefile index a25cfff..1bf8066 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,12 @@ -all: average +all: average convert_to_ints average: average.c cmaybe.h $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< +convert_to_ints: convert_to_ints.c cmaybe.h + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $< + clean: - rm -f average + rm -f average convert_to_ints .PHONY: all clean diff --git a/cmaybe.h b/cmaybe.h index bdfb824..0a82c15 100644 --- a/cmaybe.h +++ b/cmaybe.h @@ -15,8 +15,89 @@ return __return_value;\ } -#define IS_VALUE(x) if((x).is_value) -#define IS_NOT_VALUE(x) if(!(x).is_value) +#define IS_VALUE(x) if ((x).is_value) +#define IS_NOT_VALUE(x) if (!(x).is_value) #define VALUE(x) (x).value +struct __free_list { + struct __free_list *next; + void *ptr; +}; +#define ENABLE_TRY() \ + struct __free_list *__allocations = NULL, *__free_list_node;\ + void *__allocation, *__old_allocation;\ + jmp_buf __try_fail_jmp_buf;\ + if (setjmp(__try_fail_jmp_buf)) {\ + TRY_FREE_ALL();\ + RETURN_NOTHING();\ + } +#define TRY_TYPE(name) MAYBE(name) __try_tmp_##name +#define TRY(name, maybe_value) (\ + __try_tmp_##name = maybe_value,\ + (__try_tmp_##name.is_value ? 0 :\ + longjmp(__try_fail_jmp_buf, 1)\ + ),\ + __try_tmp_##name.value\ +) + +#define TRY_MEMALLOC(allocator, ...) (\ + __free_list_node = malloc(sizeof(struct __free_list)),\ + (__free_list_node == NULL ? longjmp(__try_fail_jmp_buf, 1) : 0),\ + __allocation = allocator(__VA_ARGS__),\ + (__allocation == NULL ? (\ + free(__free_list_node),\ + longjmp(__try_fail_jmp_buf, 1)\ + ) : (\ + __free_list_node->next = __allocations,\ + __free_list_node->ptr = __allocation,\ + __allocations = __free_list_node\ + )),\ + __allocation\ +) +#define TRY_MALLOC(size) TRY_MEMALLOC(malloc, size) + +static void __remove_free_list(struct __free_list **head, void *ptr) { + struct __free_list **current = head; + while (*current != NULL) { + if (current[0]->ptr == ptr) { + *current = current[0]->next; + break; + } + current = ¤t[0]->next; + } +} +#define TRY_FREE(allocation) (\ + free(allocation),\ + __remove_free_list(&__allocations, allocation)\ +) +#define TRY_FREE_ALL() \ + while (__allocations != NULL) {\ + struct __free_list *current = __allocations;\ + free(current->ptr);\ + __allocations = current->next;\ + free(current);\ + } + +static void __replace_free_list(struct __free_list **head, void *from, void *to) { + struct __free_list **current = head; + while (*current != NULL) { + if (current[0]->ptr == from) { + current[0]->ptr = to; + break; + } + current = ¤t[0]->next; + } +} +#define TRY_MEMREALLOC(reallocator, old, ...) (\ + __old_allocation = old,\ + __allocation = reallocator(old, __VA_ARGS__),\ + (__allocation == NULL ? (\ + longjmp(__try_fail_jmp_buf, 1)\ + ) : \ + __replace_free_list(&__allocations, __old_allocation, __allocation)\ + ),\ + __allocation\ +) +#define TRY_REALLOC(old, size) TRY_MEMREALLOC(realloc, old, size) + #endif diff --git a/convert_to_ints.c b/convert_to_ints.c new file mode 100644 index 0000000..2094d56 --- /dev/null +++ b/convert_to_ints.c @@ -0,0 +1,110 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include + +#include "cmaybe.h" + +MAYBE_TYPE(voidptr, void *); + +MAYBE(voidptr) strchr_maybe(const void *s, int c) { + ENABLE_RETURN(voidptr); + void *location = strchr(s, c); + if (location == NULL) { + RETURN_NOTHING(); + } else { + RETURN_VALUE(location); + } +} + +MAYBE_TYPE(intmax_t, intmax_t); + +MAYBE(intmax_t) str2int(const char *string) { + ENABLE_RETURN(intmax_t); + char *endptr; + intmax_t num = strtoimax(string, &endptr, 10); + + if (*endptr == '\0' && string[0] != '\0') { + RETURN_VALUE(num); + } else { + RETURN_NOTHING(); + } +} + +struct intmax_t_array { + intmax_t *data; + size_t length; + size_t alloc_size; +}; + +MAYBE_TYPE(intmax_t_array, struct intmax_t_array); + +MAYBE(intmax_t_array) convert_to_numbers(char *line) { + ENABLE_RETURN(intmax_t_array); + ENABLE_TRY(); + TRY_TYPE(intmax_t); + + struct intmax_t_array numbers; + numbers.length = 0; + numbers.alloc_size = 64 * sizeof(intmax_t); + numbers.data = TRY_MALLOC(numbers.alloc_size * sizeof(intmax_t)); + + char *strtok_saveptr = NULL; + for (;;) { + char *num_str; + if (strtok_saveptr == NULL) { + num_str = strtok_r(line, " ", &strtok_saveptr); + } else { + num_str = strtok_r(NULL, " ", &strtok_saveptr); + } + + if (num_str == NULL) { + break; + } + + intmax_t num = TRY(intmax_t, str2int(num_str)); + + size_t index = numbers.length; + numbers.length++; + if(numbers.alloc_size / sizeof(intmax_t) < numbers.length) { + if(SIZE_MAX / 2 < numbers.alloc_size) { + TRY_FREE(numbers.data); + RETURN_NOTHING(); + } + numbers.alloc_size *= 2; + numbers.data = TRY_REALLOC(numbers.data, numbers.alloc_size); + } + numbers.data[index] = num; + } + + RETURN_VALUE(numbers); +} + +int main(void) { + size_t line_size = 0; + char *line = NULL; + + ssize_t line_len; + while ((line_len = getline(&line, &line_size, stdin)) > 0) { + MAYBE(voidptr) newline = strchr_maybe(line, '\n'); + IS_VALUE(newline) { + *(char*)VALUE(newline) = '\0'; + } + + MAYBE(intmax_t_array) numbers = convert_to_numbers(line); + IS_VALUE(numbers) { + for (size_t i = 0; i < VALUE(numbers).length; i++) { + printf("%jd ", VALUE(numbers).data[i]); + } + printf("\n"); + } else { + printf("Error in conversion\n"); + } + } + + return 0; +}