/* 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);

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

/* Gesamtlaenge aller Zeichenketten: */

int length;			/* EVIL GLOBAL VARIABLE */

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

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

int num_H, num_G;		/* EVIL GLOBAL VARIABLES */

void do_count_H_and_G(char *text)
{
  switch (text[0]) {
  case 'H':
    num_H++;
    break;
  case 'G':
    num_G++;
    break;
  }
}

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