/* linkedlist3.c -- Einfach verkettete Liste von Zeichenketten,
                    Funktion hoeherer Ordnung mit void*-Datenzeiger.
*/

#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, void *data);

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

/* Gesamtlaenge aller Zeichenketten: */

void add_to_length(char *text, void *data)
{
  int *length_p = data;
  (*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. */

struct count_H_and_G_data {
  int num_H;
  int num_G;
};

void do_count_H_and_G(char *text, void *data)
{
  struct count_H_and_G_data *hgdata = data;
  switch (text[0]) {
  case 'H':
    hgdata->num_H++;
    break;
  case 'G':
    hgdata->num_G++;
    break;
  }
}

void count_H_and_G(struct string_list *list,
		   int *num_H_p,
		   int *num_G_p)
{
  struct count_H_and_G_data hgdata;
  hgdata.num_H = 0;
  hgdata.num_G = 0;
  string_list_for_each(list, do_count_H_and_G, &hgdata);
  *num_H_p = hgdata.num_H;
  *num_G_p = hgdata.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;
}
