+#include "libft.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+typedef struct
+{
+ unsigned char bytes[4];
+} t_symbol;
+
+typedef struct
+{
+ t_symbol preceding;
+ t_symbol subsequent;
+} t_relation;
+
+size_t get_utf8_size(char c)
+{
+ if (~c & 0x80)
+ {
+ return (1);
+ }
+ if ((c & 0xF0) == 0xF0)
+ {
+ return (4);
+ }
+ if ((c & 0xF0) == 0xE0)
+ {
+ return (3);
+ }
+ if ((c & 0xF0) == 0xC0)
+ {
+ return (2);
+ }
+ return (0);
+}
+
+size_t get_symbol_size(t_symbol symbol)
+{
+ return (get_utf8_size(symbol.bytes[0]));
+}
+
+int is_symbol_null(t_symbol symbol)
+{
+ return (symbol.bytes[0] == '\0');
+}
+
+void copy_symbol(const char *string, t_symbol *symbol)
+{
+ ft_bzero(&symbol->bytes, sizeof(symbol->bytes));
+ ft_memcpy(&symbol->bytes, string, get_utf8_size(*string));
+ return ;
+}
+
+t_symbol *decode_utf8(const char *string)
+{
+ t_symbol *result;
+ size_t i;
+
+ result = malloc((ft_strlen(string) + 1) * sizeof(t_symbol));
+ if (!result)
+ {
+ return (NULL);
+ }
+ i = 0;
+ while (*string)
+ {
+ copy_symbol(string, result + i);
+ string += get_symbol_size(result[i]);
+ ++i;
+ }
+ copy_symbol(string, result + i);
+ return (result);
+}
+
+int is_same_symbol(t_symbol a, t_symbol b)
+{
+ int ret;
+ size_t i;
+
+ ret = 1;
+ i = 0;
+ while (i < sizeof(a.bytes) / sizeof(a.bytes[0]))
+ {
+ ret = ret && (a.bytes[i] == b.bytes[i]);
+ ++i;
+ }
+ return (ret);
+}
+
+int get_relation(const char *first, const char *second, t_relation *relation)
+{
+ size_t i;
+ t_symbol *decoded_first;
+ t_symbol *decoded_second;
+
+ decoded_first = decode_utf8(first);
+ decoded_second = decode_utf8(second);
+ if (!decoded_first || !decoded_first)
+ {
+ free(decoded_first);
+ free(decoded_second);
+ return (1);
+ }
+ i = 0;
+ while (is_same_symbol(decoded_first[i], decoded_second[i]))
+ {
+ ++i;
+ }
+ relation->preceding = decoded_first[i];
+ relation->subsequent = decoded_second[i];
+ free(decoded_first);
+ free(decoded_second);
+ return (0);
+}
+
+void remove_invalid_relations(t_vec *relations)
+{
+ size_t i;
+ const t_relation *relation;
+
+ i = relations->size;
+ while (i > 0)
+ {
+ --i;
+ relation = ft_vec_caccess(relations, i);
+ if (is_symbol_null(relation->subsequent)
+ || is_symbol_null(relation->preceding))
+ {
+ ft_vec_erase(relations, i, NULL);
+ }
+ }
+ return ;
+}
+
+int create_relation_list(t_vec *relations, int fd)
+{
+ t_relation relation;
+ char *prev_word;
+ char *word;
+
+ prev_word = get_next_line(fd);
+ word = get_next_line(fd);
+ while (word)
+ {
+ if (get_relation(prev_word, word, &relation)
+ || ft_vec_append(relations, &relation))
+ {
+ free(prev_word);
+ free(word);
+ return (1);
+ }
+ free(prev_word);
+ prev_word = word;
+ word = get_next_line(fd);
+ }
+ free(prev_word);
+ remove_invalid_relations(relations);
+ return (0);
+}
+
+t_symbol find_symbol_that_only_precedes(const t_vec *relations)
+{
+ size_t i;
+ const t_relation *relation;
+ t_symbol symbol;
+
+ relation = ft_vec_caccess(relations, 0);
+ symbol = relation->preceding;
+ i = 1;
+ while (i < relations->size)
+ {
+ relation = ft_vec_caccess(relations, i);
+ if (is_same_symbol(symbol, relation->subsequent))
+ {
+ symbol = relation->preceding;
+ i = 0;
+ }
+ ++i;
+ }
+ return (symbol);
+}
+
+void remove_symbol_relations(t_vec *relations, t_symbol symbol)
+{
+ size_t i;
+ const t_relation *relation;
+
+ i = relations->size;
+ while (i > 0)
+ {
+ --i;
+ relation = ft_vec_caccess(relations, i);
+ if (is_same_symbol(symbol, relation->preceding))
+ {
+ ft_vec_erase(relations, i, NULL);
+ }
+ }
+ return ;
+}
+
+int sort_alphabet(t_vec *relations, t_vec *alphabet)
+{
+ t_symbol symbol;
+ const t_relation *relation;
+
+ while (relations->size > 1)
+ {
+ symbol = find_symbol_that_only_precedes(relations);
+ remove_symbol_relations(relations, symbol);
+ if (ft_vec_append(alphabet, &symbol))
+ {
+ return (1);
+ }
+ }
+ relation = ft_vec_caccess(relations, 0);
+ if (ft_vec_append(alphabet, &relation->preceding)
+ || ft_vec_append(alphabet, &relation->subsequent))
+ {
+ return (1);
+ }
+ return (0);
+}
+
+void print_symbol(t_symbol symbol)
+{
+ write(STDOUT_FILENO, symbol.bytes, get_symbol_size(symbol));
+ return ;
+}
+
+void print_alphabet(const t_vec *alphabet)
+{
+ size_t i;
+
+ i = 0;
+ while (i < alphabet->size)
+ {
+ print_symbol(*(const t_symbol *)ft_vec_caccess(alphabet, i));
+ ++i;
+ }
+ write(STDOUT_FILENO, "\n", 1);
+ return ;
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+ int input_fd;
+ t_vec relations;
+ t_vec alphabet;
+
+ if (argc == 1)
+ {
+ input_fd = STDIN_FILENO;
+ }
+ else
+ {
+ input_fd = open(argv[1], O_RDONLY);
+ if (input_fd < 0)
+ {
+ return (1);
+ }
+ }
+ ft_vec_init(&relations, sizeof(t_relation));
+ ft_vec_init(&alphabet, sizeof(t_symbol));
+ if (create_relation_list(&relations, input_fd) == 0
+ && sort_alphabet(&relations, &alphabet) == 0)
+ {
+ print_alphabet(&alphabet);
+ ret = 0;
+ }
+ else
+ {
+ ret = 2;
+ }
+ ft_vec_free(&relations, NULL);
+ ft_vec_free(&alphabet, NULL);
+ if (input_fd != STDIN_FILENO)
+ {
+ close(input_fd);
+ }
+ return (ret);
+}