Archive for August 2007

Haskell and C—structs

When creating Haskell bindings for a C library one will sooner or later have to deal with ’structs’. Let’s look at how it can be done using hsc2hs.

Here’s a somewhat silly struct that’ll do for this example:

typedef struct {
    int a;
    int b;
} Foo;

It goes the file foo.h. I need some way of making sure that the data was passed properly from Haskell to C so here’s a declaration for a function to print an instance of Foo:

void print_foo(Foo *);

The actual implementation of print_foo goes into foo.c:

void
print_foo(Foo *f)
{
    printf("%s\n", __FUNCTION__);
    printf("f->a: %i\n", f->a);
    printf("f->b: %i\n", f->b);
}

No surprises so far. Now onto the Haskell side of things. First some basic setup:

{-# OPTIONS -ffi #-}
module Main
    where

import Foreign
import Foreign.C.Types

That makes sure I don’t forget to tell GHC that I’m using the foreign function interface (FFI) and imports everything I need for the rest. hsc2hs needs to know about the struct so I simply include the header file. I also need the Haskell representation of Foo, called Bar here, and for convenience I add a type for a pointer to Bar:

#include "foo.h"

data Bar = Bar { a :: Int, b :: Int }
type BarPtr = Ptr (Bar)

Now I’m ready to add the declaration of the “foreign” function:

foreign import ccall "static foo.h print_foo"
    f_print_foo :: BarPtr -> IO ()

Looking through the standard modules it isn’t completely obvious how to create a BarPtr for passing to f_print_foo. Whit the help of people on #haskell I found with, which has the type Storable a => a -> (Ptr a -> IO b) -> IO b. That means I have to make Bar a Storable. According to the documentation on Storable and some experimentation I found that for this particular example I only need full implementations of sizeOf, alignment and poke:

instance Storable Bar where
    sizeOf _ = (#size Foo)
    alignment _ = alignment (undefined :: CInt)
    peek _ = error "peek is not implemented"
    poke ptr (Bar a' b') = do
        (#poke Foo, a) ptr a'
        (#poke Foo, b) ptr b'

([Edited 09-08--2007 07:43 BST] See DeeJay’s comment below for an explanation of the definition of alignment.)

Using with every time I have to call f_print_foo will get tiring so here’s a function that’s a bit more convenient to use:

printFoo b = with b f_print_foo

Now I can write a small main function to test it all:

main = printFoo $ Bar { a=17, b=47 }

It works beautifully. However it’s very limited since it only covers the cases when a C function takes a pointer to a struct as a pure in argument. What about inout? (It’ll be easy to see how to deal with out arguments once the inout case is covered.) So, here’s a C function that adds 1 to one of the members in the struct:

void
add_a(Foo *f)
{
    printf("%s\n", __FUNCTION__);
    f->a++;
}

Of course a declaration in the header file is needed as well, but that’s pretty obvious so I’ll skip it here. The declaration of the foreign function is as simple as for f_print_foo:

foreign import ccall "static foo.h add_a"
    f_add_a :: BarPtr -> IO ()

Now comes the interesting part. Writing a convenience function for f_add_a isn’t as straight forward as for f_print_foo. I think something with the type Bar -> IO Bar would be useful. with creates a temporary BarPtr for the duration of the call which means I have to have an inner function that takes the Bar part out of the BarPtr and returns it inside IO. Luckily peek does exactly that. Adding an implementation of it means that Bar as a Storable is implemented like this:

instance Storable Bar where
    sizeOf _ = (#size Foo)
    alignment _ = 1 -- ???
    peek ptr = do
        a' <- (#peek Foo, a) ptr
        b' <- (#peek Foo, b) ptr
        return Bar { a=a', b=b' }
    poke ptr (Bar a' b') = do
        (#poke Foo, a) ptr a'
        (#poke Foo, b) ptr b'

And the convenience function for f_add_a can be written like this:

addA b = with b $ \ p -> f_add_a p >> peek p

Then I can modify the main function to test this as well:

main = do
    b <- return $ Bar { a=17, b=47 }
    printFoo b
    d <- addA b
    printFoo b
    printFoo d

Indeed, produces the expected out put:

print_foo
f->a: 17
f->b: 47
add_a
print_foo
f->a: 17
f->b: 47
print_foo
f->a: 18
f->b: 47

Pure out arguments can be handled using alloca with a function similar to the one I pass to with in addA above.

Links and stuff (3/8/2007)

It’s been a while but my list of links to put out there is starting to get a bit too long.

Here’s another example of how wrong the patent system is. We really don’t need software patents in Europe! There seems to be some hope for the situation in the States though. We need more stories like that!

Some Linux related things. I suppose “military intelligence” isn’t such an oxymoron after all, at least not in Sweden. If you want to learn Linux, here are some tips. If you are so unfortunate as to be a Linux user forced to work on Windows then here are some tips for you.

There’s always some interesting things going on in the DRM world. How’s this for a story? Large music company sticks dodgy software from small company on CDs so that their customers’ unwittingly installs said software when trying to play the CD on their computer. Then it turns out that the software is dodgy and the large company is taken to court in class action suits all over the world. Now, who’s to blame? The large company that made the amazingly bad decision to treat their customers like criminals? Not if you’re Sony! Here’s a bonus article on DRM, a bit of scare mongering surrounding Microsoft’s use of “trusted computing”. Yes, technology can be used in bad ways, but I doubt even Microsoft would be able to stick to such a bad use of technology for long. Call me an optimist! I’m hopelessly late. Here’s an excellent explanation of why DRM is so hard from a technical POV.

I’ve been hoarding links on how to opt out of the NHS database here in the UK. They could turn out to be useful.

I doubt I’ll ever need this.

Looking to become a maintainer of some free software? Look no further.

If you live in the UK and shop online you should know your rights.

A funny story about security.

How’s this for ending on a funny/happy note? It seems the RFID tags in passports can be used to crash the RFID readers.

OSCON videos are available

I’m quite likely the last one to realise this but the OSCON 2007 videos are available on blip.tv. Search for “oscon” to find them. I’ve heard Simon Peyton-Jones’s tutorial on Haskell was very well received, I just downloaded the two parts to watch in the weekend.

On organising photos and Flickr

We’ve had a very poor organisation of our photos. Sometimes I’ve copied the photos off the camera into folders named after when the pictures were taken, sometimes I’ve just copied them into a folder based on the date I did the copying. Yet other times I couldn’t even be bothered to create a new folder, or rename any of the folders I copied off the camera. My wife has been using Yahoo Photos and for that we’ve sometimes created specific folders with copies of photos for uploading into albums. Well, it was a right mess.

With Yahoo’s purchase of Flickr they are now closing down Yahoo Photos so this would be an excellent opportunity to not only move the albums but also organise all the photos locally and maybe even back them up. After reading John Goerzen’s review of Flickr I decided that Flickr was the way to go. I started with looking at some photo management software. Reading reviews gave me the feeling that what I wanted wasn’t so much a flashy GUI tool for playing around with our photos; what I wanted was a tool that would organise them for me into a hierarchy of folders. F-spot can do that but it kept on crashing on me. Luckily I came across photoname, it’s a simple command line tool that does exactly what I want–copy photos into a folder hierarchy based on the EXIF data. Due to our terrible organisation we had several copies of the same photo in different places so it required a lot of manual labour to get all photos in order.

Once that was done I started looking into how to upload everything to Flickr. I had already seen flickrfs but I had never tried. Irritatingly it adds the tag flickrfs to all pictures one uploads, thank goodness it’s FOSS; I made a patch. I decided to tag all photos with year, month and date for now. Due to the hierarchy created by photoname I ended up running the following little shell/python snippet in each “year folder”:

for d in *; do
    cp --verbose ${d}/* ~/tmp/flickrfs/stream:$(python -c \
    "print ':'.join(map(''.join, zip(['Y', 'M', 'D'], ‘${d}’.split(’-'))))”)/
done

After quite a long wait I now have almost all the pictures uploaded to Flickr.