/* linkedlist2.c -- Einfach verkettete Liste von Zeichenketten,
                    Funktion hoeherer Ordnung. */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

struct string_node {
  char *text;
  struct string_node *next;
};

struct string_list {
  struct string_node *head;
};


struct string_list *new_string_list()
{
  struct string_list *list = malloc(sizeof(struct string_list));
  list->head = NULL;
  return list;
}

void free_string_list(struct string_list *list)
{
  struct string_node *node = list->head;
  free(list);
  while (node != NULL) {
    struct string_node *next = node->next;
    free(node->text);
    free(node);
    node = next;
  }
}

void string_list_push(struct string_list *list, char *text)
{
  struct string_node *node = malloc(sizeof(struct string_node));
  node->text = text;
  node->next = list->head;
  list->head = node;
}

/* Funktion zum Iterieren */

typedef void (*string_function)(char *text, int *data);

void string_list_for_each(struct string_list *list,
			  string_function function,
			  int *data)
{
  struct string_node *node = list->head;
  while (node != NULL) {
    (*function)(node->text, data);
    node = node->next;
  }
}

typedef void (*string_function_2)(char *text, int *data1, int *data);

void string_list_for_each_2(struct string_list *list,
			    string_function_2 function,
			    int *data1, int *data2)
{
  struct string_node *node = list->head;
  while (node != NULL) {
    (*function)(node->text, data1, data2);
    node = node->next;
  }
}

/* Gesamtlaenge aller Zeichenketten: */

void add_to_length(char *text, int *length_p)
{
  *length_p += strlen(text);
}
			  
int total_length(struct string_list *list)
{
  int length = 0;
  string_list_for_each(list, add_to_length, &length);
  return length;
}

/* Zaehlt Anzahl Zeichenketten, die mit H bzw. G beginnen. */

void do_count_H_and_G(char *text, int *num_H_p, int *num_G_p)
{
  switch (text[0]) {
  case 'H':
    (*num_H_p)++;
    break;
  case 'G':
    (*num_G_p)++;
    break;
  }
}

void count_H_and_G(struct string_list *list,
		   int *num_H_p,
		   int *num_G_p)
{
  int num_H = 0;
  int num_G = 0;
  string_list_for_each(list, do_count_H_and_G, &num_H, &num_G);
  *num_H_p = num_H;
  *num_G_p = num_G;
}

int main ()
{
  struct string_list *list = new_string_list();
  string_list_push(list, strdup("Hello"));
  string_list_push(list, strdup("Good-bye"));
  printf("Gesamtlaenge: %d\n", total_length(list));
  {
    int num_H, num_G;
    count_H_and_G(list, &num_H, &num_G);
    printf("Anzahl H...: %d,  Anzahl G...: %d\n", num_H, num_G);
  }
  return 0;
}
