Task: Alternade words

C: #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#define WORD_BUF_SIZE 30
#define MIN_WORD_SIZE 6


void fail(void) {
    fprintf(stderr, "%s\n", strerror(errno));
    exit(42);
}


struct trie_node {
    char ch, final;
    struct trie_node *parent, *sibling, *root, *child; 
};

struct trie_node *alloc_node() {
    struct trie_node *t = calloc(1, sizeof(struct trie_node));
    if (t == NULL) fail();
    return t;
}

struct trie_node *make_sibling(struct trie_node *node) {
    struct trie_node *t = alloc_node();
    node->sibling = t;
    t->ch = node->ch;
    t->parent = node->parent;
    t->root = node->root;
    return t;
}

struct trie_node *make_child(struct trie_node *node, char ch) {
    struct trie_node *t = alloc_node();
    t->parent = node;
    t->ch = ch;
    t->root = node->root;
    node->child = t;
    return t;
}


struct trie_node *add_word(struct trie_node *root, const char *word) {
    struct trie_node *cur = root;
    for (; *word; word++) {
        while (cur->child == NULL || cur->child->ch != *word) {
            if (cur->child == NULL) {
                
                make_child(cur, *word);
            } else {
                
                if (cur->sibling == NULL) make_sibling(cur);
                cur = cur->sibling;
            }
        }
        
        
        cur = cur->child;
    }
    cur->final = 1; 
    return cur;
}


struct trie_node *find_word(struct trie_node *root, const char *word) {
    struct trie_node *cur = root;
    for (; *word && cur; word++) {
        while (cur != NULL && cur->child != NULL && cur->child->ch != *word) {
            cur = cur->sibling;
        }
        if (cur == NULL) return NULL; 
        cur = cur->child;
    }
    if (cur && cur->final) return cur;
    else return NULL;
}


void scan_trie(struct trie_node *node, void callback(struct trie_node *)) {
    if (node == NULL) return;
    if (node->final) callback(node);
    scan_trie(node->child, callback);
    scan_trie(node->sibling, callback);
}


char *get_word(struct trie_node *node, char *buffer) {
    char t, *ch = buffer, *s = buffer;
    for (; node != NULL; node=node->parent) *ch++ = node->ch;
    for (ch-=2; ch >= s; ch--, s++) *ch ^= *s ^= *ch ^= *s;
    return buffer;
}


void check_alternade(struct trie_node *node) {
    static char word[WORD_BUF_SIZE], even[WORD_BUF_SIZE], odd[WORD_BUF_SIZE];
    char *p_even = even, *p_odd = odd;
    int i;
    
    
    if (strlen(get_word(node, word)) < MIN_WORD_SIZE) return;
    
    
    for (i=0; word[i]; i++) {
        if (i & 1) *p_odd++ = word[i];
        else *p_even++ = word[i];
    }
    *p_odd = *p_even = '\0';
        
    
    if (find_word(node->root, even) && find_word(node->root, odd)) {
        printf("%-20s%-10s%-10s\n", word, even, odd);
    }
}
          
int main(void) {
    struct trie_node *root = alloc_node();
    root->root = root;
    char word[WORD_BUF_SIZE], *nl;
    
    
    while (!feof(stdin)) {
        fgets(word, WORD_BUF_SIZE, stdin);
        if (nl = strchr(word, '\n')) *nl = '\0';  
        add_word(root, word);
    }
    
    
    scan_trie(root, check_alternade);
    return 0;
}











Ada: with Ada.Text_Io;
with Ada.Containers.Indefinite_Ordered_Maps;

procedure Alternade_Words is
   use Ada.Text_Io;

   package String_Maps is
     new Ada.Containers.Indefinite_Ordered_Maps (Key_Type     => String,
                                                 Element_Type => String);

   function Get_Odd (Word : String) return String is
      Odd : String (1 .. (Word'Length + 1) / 2);
   begin
      for Index in Odd'Range loop
         Odd (Index) := Word (1 + 2 * (Index - 1));
      end loop;
      return Odd;
   end Get_Odd;

   function Get_Even (Word : String) return String is
      Even : String (1 .. Word'Length / 2);
   begin
      for Index in Even'Range loop
         Even (Index) := Word (1 + 1 + 2 * (Index - 1));
      end loop;
      return Even;
   end Get_Even;

   Filename : constant String := "unixdict.txt";
   Words    : String_Maps.Map;
   File     : File_Type;
begin
   Open (File, In_File, Filename);
   while not End_Of_File (File) loop
      declare
         Word : constant String := Get_Line (File);
      begin
         Words.Insert (Word, Word);
      end;
   end loop;
   Close (File);

   for Word of Words loop
      declare
         Odd  : constant String := Get_Odd  (Word);
         Even : constant String := Get_Even (Word);
      begin
         if
           Word'Length >= 6       and then
             Words.Contains (Odd) and then
             Words.Contains (Even)
         then
            Put (Word);
            Set_Col (15); Put (Odd);
            Set_Col (25); Put (Even);
            New_Line;
         end if;
      end;
   end loop;
end Alternade_Words;