The typical usage consists of the following steps:
  1. Creates an interface file describing functions and datatypes
  2. Invoking kdirect on a created file - the .hsc file is generated. This is a temporary file - used only to run hsc2hs from QForeign library on it
  3. Invoking hsc2hs on a generated file - the .hs file is generated. This is the file with interfaced C functions
  4. Compiling the .hs file
We will go through these steps now.
The library we will interface is called Flag (not very useful, but quite illustrative):
"flag.h"

#ifndef _flag_h
#define _flag_h

typedef long Age;
typedef char Woman;

typedef enum 
{
  White = 7, Black 
} Color;

typedef struct
{
  Color first, second;
} Flag;

typedef struct 
{
  Age age;
  char *name;
  Woman isWoman;
} Person;

extern Person *NewPerson(Age age, const char *name, Woman isWoman);
extern void destructor(Person *person);
extern Flag *NewFlag(Color col1, const char *col2);
extern void getRidOf(Flag *f);
extern char *flagName(Flag *f);

#endif

"flag.c"


#include 
#include 
#include 

#include "flag.h"

Person *NewPerson(Age age, const char *name, Woman isWoman)
{
  Person *p = (Person *)malloc(sizeof(Person));
  p->age = age;
  p->name = (char *)malloc(strlen(name) + 1);
  p->isWoman = isWoman;
  strcpy(p->name, name);
  printf("%s was born and lived for %d years\n", p->name, p->age);
  return p;
}

void destructor(Person *person)
{
  free(person->name);
  free(person);
  printf("Another one bites the dust\n");
}

Flag *NewFlag(Color col1, const char *col2)
{
    Flag *f = (Flag *)malloc(sizeof(Flag));
    f->first = col1;
    if (strcmp(col2, "white"))
        f->second = Black;
    else
        f->second = White;
    return f;
}

void getRidOf(Flag *f)
{
      free(f);
      printf("Another flag bites the dust\n");
}
  
char *flagName(Flag *f)
{
      char *ret = (char *)malloc(100);
      if (f->first == White)
          strcpy(ret, "White flag");
      else
          strcpy(ret, "Black flag");
      return ret;
}

The sample program using the Flag library:

#include 
#include 
#include "Flag.h"

main()
{
  Color a = black;
  Flag *f;
  char *s;
  Person *p;
      
  f = NewFlag(a, "white");
  s = flagName(f);
  printf("%s\n", s);
  p = newPerson(23, "Agatha Smith", 1);
  printf("My name is %s and I'm %d years old.\n", p->name, p->age);
  if (p->isWoman)
    printf("I'm a woman!!!\n");
  
  destructor(p);
  free(s);
  getRidOf(f);
}
  
In this little library we have both an abstract pointer - that's a Flag struct - Haskell user doesn't know anything about its internals and a normal struct - Person. Both have finalizers - functions to run when we no longer need the pointer. We cannot, however, make struct pointer finalize itself automagically - we have to do it manually, when we no longer need it.
Note that the caller is responsible for freeing the flagName result. getRidOf must be called to free a Flag pointer, when we no longer need it.
Now, to interface the Flag library to Haskell we create Flag.khs file (comments are marked by //, similarly to C++). The translation is quite straightforward:
"Flag.khs"

#include "flag.h"

module Flag where

abstractPtr Flag * finalizer getRidOf;

enum Color { Black, White };

typedef Int Age;
typedef Bool Woman;

struct Person
{
  Age age;
  string name;
  Woman isWoman;
};

Person *NewPerson(Age age, string person, Woman isWoman);
void destructor(Person *person);
Flag *NewFlag(enum Color col1, string col2);
void getRidOf(Flag *flag);
[free] string flagName(Flag *flag);

And that's all! Now we run:
kdirect Flag.khs
A Flag.hsc file is created. Then we run:
hsc2hs Flag.hsc
And Flag.hs file is created - with the Flag C library interfaced into Haskell. Note that KDirect changes first letters to (upper/lower)case when needed.
Let's take a look at the generated code:
typedef Int Age;
typedef Bool Woman;
We have here C typedefs - Age and Woman - interfaced to Haskell. Note that in typedef declaration in .khs file you tell kdirect what's the Haskell counterpart of C type - Bool in case of Woman, Int in case of Age. KDirect will extract C type information by itself.
data Flag = FlagTag
type FlagPtr = ForeignPtr Flag

data Person = Person
  Int  -- age
  String  -- name
type PersonPtr = Ptr Person
For each structure named Foo, two Haskell types are generated: Foo and FooPtr. The first one consists of the valid datatype, in case of a concrete structure, and a useless tag in case of an abstract pointer. The second one is a Haskell counterpart of a corresponding C pointer. This is what C functions can take as an argument, and what they can return:
newPerson :: Int -> String -> IO (PersonPtr)
destructor :: PersonPtr -> IO (())
newFlag :: Color -> String -> IO (FlagPtr)
getRidOf :: FlagPtr -> IO (())
flagName :: FlagPtr -> IO (String)
To dereference a non-abstract Haskell pointer we use a peek function:
peek :: Ptr a -> IO a

WARNING!!!


Be warned that any interfaced C function doesn't have to be a well-behaved function. It is a C function - which means it can modify memory to which points its pointer argument. Thus, in the following piece of code:
do
  personPtr <- newPerson 23 "foo"
  person1 <- peek personPtr
  destructor personPtr
  person2 <- peek personPtr

person1 can be different from person2. You have been warned.
Currently in and out modifiers are supported. Look at Notes file in the source directory to see how to handle this case, but be warned that the syntax can and possibly will change. Now we can write our program in Haskell:
module Main where

import Flag

main = let
  a :: Color
  a = black in do
    f <- newFlag a "white"
    s <- flagName f
    putStrLn s
    personPtr <- newPerson 23 "John Smith"
    Person age name <- peek personPtr
    putStrLn $ "My name is " ++ name ++ " and I'm " ++ (show age) ++ " years old."
    destructor personPtr
and compile everything:
ghc -c Flag.hs -fglasgow-exts `qforeign-config --hcflags`
gcc -c flag.c
ghc -c Main.hs -fglasgow-exts `qforeign-config --hcflags`
ghc Main.o Flag.o flag.o -o flag -fglasgow-exts `qforeign-config --ldflags --ldlibs`
Voila! We've got a working program. If you have any questions about this tutorial or feel that it isn't clear enough, email me.
Wojciech Moczydlowski, Jr