
Jefferson Heard wrote:
I have the following functions in C:
OGRErr OGR_G_CreateFromWkb (unsigned char *, OGRSpatialReferenceH, OGRGeometryH *, int) OGRErr OGR_G_CreateFromWkt (char **, OGRSpatialReferenceH, OGRGeometryH *) void OGR_G_DestroyGeometry (OGRGeometryH) OGRGeometryH OGR_G_CreateGeometry (OGRwkbGeometryType)
The normal sequence of calls is
OGRGeometryH handle = OGR_G_CreateGeometry(SOME_TYPE); // do stuff OGR_G_DestroyGeometry(handle);
OR
OGR_G_CreateFromWkb(blob, ref, &handle, 0); // do stuff OGR_G_DestroyGeometry(handle);
As you can see, in one case, I have to pass in a pointer to the returned handle, and not just the handle. How can I accomplish this feat using a single type?
I had
data OGRGeometryH type Geometry = Ptr OGRGeometryH
Almost: Assuming that OGRGeometryH is some sort of pointer, e.g. typedef struct OGRGeometry *OGRGeometryH you could write:
data OGRGeometry type OGRGeometryH = Ptr OGRGeometry
where OGRGeometryH is the type that you API exports.
foreign import ccall oGR_G_CreateFromWkb :: ...whatever... -> Ptr OGRGeometryH -> OGRErr
Note that Ptr OGRGeometryH is in fact a pointer to a pointer, just as the C type demands. When calling such a procedure you must first allocate space. This is most elegantly done using alloca (I have added some basic error handling, otherwise the value returned might be undefined):
createFromWbk :: ...argtypes... -> Either OGRErr OGRGeometryH createFromWbk ...args... = alloca $ \ptr -> do -- in this code block you can peek and poke the ptr; -- space will be deallocated after block exits res <- oGR_G_CreateFromWkb ...args... ptr if checkResultOK res then do -- this can be shortened to: liftM Right $ peek ptr -- or: peek ptr >>= return . Right h <- peek ptr return (Right h) else return (Left res)
(Instead of returning an Either type you could throw exceptions, but you didn't ask about error handling, did you ?-) Cheers Ben