       ndevs = length devs
       cndevs = fromIntegral ndevs
 
--- -----------------------------------------------------------------------------
+#c
+enum CLProgramInfo {
+  cL_PROGRAM_REFERENCE_COUNT=CL_PROGRAM_REFERENCE_COUNT,
+  cL_PROGRAM_CONTEXT=CL_PROGRAM_CONTEXT,
+  cL_PROGRAM_NUM_DEVICES=CL_PROGRAM_NUM_DEVICES,
+  cL_PROGRAM_DEVICES=CL_PROGRAM_DEVICES,
+  cL_PROGRAM_SOURCE=CL_PROGRAM_SOURCE,
+  cL_PROGRAM_BINARY_SIZES=CL_PROGRAM_BINARY_SIZES,
+  cL_PROGRAM_BINARIES=CL_PROGRAM_BINARIES,
+  };
+#endc
+{#enum CLProgramInfo {upcaseFirstLetter} #}
+
+getProgramInfoSize :: CLProgram -> CLProgramInfo_ -> IO (Either CLError CSize)
+getProgramInfoSize prg infoid = alloca $ \(value_size :: Ptr CSize) -> do
+  errcode <- raw_clGetProgramInfo prg infoid 0 nullPtr value_size
+  if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+    then fmap Right $ peek value_size
+    else return . Left . toEnum . fromIntegral $ errcode
+  
+-- | Return the program reference count. The reference count returned should be
+-- considered immediately stale. It is unsuitable for general use in
+-- applications. This feature is provided for identifying memory leaks.
+clGetProgramReferenceCount :: CLProgram -> IO (Either CLError CLuint)
+clGetProgramReferenceCount prg = wrapGetInfo (\(dat :: Ptr CLuint) 
+                                              -> raw_clGetProgramInfo prg infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_PROGRAM_REFERENCE_COUNT
+      size = fromIntegral $ sizeOf (0::CLuint)
+
+-- | Return the context specified when the program object is created.
+clGetProgramContext :: CLProgram -> IO (Either CLError CLContext)
+clGetProgramContext prg = wrapGetInfo (\(dat :: Ptr CLContext) 
+                                       -> raw_clGetProgramInfo prg infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_PROGRAM_CONTEXT
+      size = fromIntegral $ sizeOf (nullPtr::CLContext)
+
+-- | Return the number of devices associated with program.
+clGetProgramNumDevices :: CLProgram -> IO (Either CLError CLuint)
+clGetProgramNumDevices prg = wrapGetInfo (\(dat :: Ptr CLuint) 
+                                       -> raw_clGetProgramInfo prg infoid size (castPtr dat)) id
+    where 
+      infoid = getCLValue CL_PROGRAM_NUM_DEVICES
+      size = fromIntegral $ sizeOf (0::CLuint)
+
+-- | Return the list of devices associated with the program object. This can be
+-- the devices associated with context on which the program object has been
+-- created or can be a subset of devices that are specified when a progam object
+-- is created using 'clCreateProgramWithBinary'.
+clGetProgramDevices :: CLProgram -> IO (Either CLError [CLDeviceID])
+clGetProgramDevices prg = do
+  sval <- getProgramInfoSize prg infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right size -> allocaArray (numElems size) $ \(buff :: Ptr CLDeviceID) -> do
+      errcode <- raw_clGetProgramInfo prg infoid size (castPtr buff) nullPtr
+      if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+        then fmap Right $ peekArray (numElems size) buff
+        else return . Left . toEnum . fromIntegral $ errcode
+    where 
+      infoid = getCLValue CL_PROGRAM_DEVICES
+      numElems s = (fromIntegral s) `div` elemSize
+      elemSize = sizeOf (nullPtr::CLDeviceID)
+
+-- | Return the program source code specified by
+-- 'clCreateProgramWithSource'. The source string returned is a concatenation of
+-- all source strings specified to 'clCreateProgramWithSource' with a null
+-- terminator. The concatenation strips any nulls in the original source
+-- strings. The actual number of characters that represents the program source
+-- code including the null terminator is returned in param_value_size_ret.
+clGetProgramSource :: CLProgram -> IO (Either CLError String)
+clGetProgramSource prg = do
+  sval <- getProgramInfoSize prg infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right n -> allocaArray (fromIntegral n) $ \(buff :: CString) -> do
+      errcode <- raw_clGetProgramInfo prg infoid n (castPtr buff) nullPtr
+      if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+        then fmap Right $ peekCString buff
+        else return . Left . toEnum . fromIntegral $ errcode
+    where 
+      infoid = getCLValue CL_PROGRAM_SOURCE
+  
+-- | Returns an array that contains the size in bytes of the program binary for
+-- each device associated with program. The size of the array is the number of
+-- devices associated with program. If a binary is not available for a
+-- device(s), a size of zero is returned.
+clGetProgramBinarySizes :: CLProgram -> IO (Either CLError [CSize])
+clGetProgramBinarySizes prg = do
+  sval <- getProgramInfoSize prg infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right size -> allocaArray (numElems size) $ \(buff :: Ptr CSize) -> do
+      errcode <- raw_clGetProgramInfo prg infoid size (castPtr buff) nullPtr
+      if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+        then fmap Right $ peekArray (numElems size) buff
+        else return . Left . toEnum . fromIntegral $ errcode
+    where 
+      infoid = getCLValue CL_PROGRAM_BINARY_SIZES
+      numElems s = (fromIntegral s) `div` elemSize
+      elemSize = sizeOf (0::CSize)
+
+{-| Return the program binaries for all devices associated with program. For
+each device in program, the binary returned can be the binary specified for the
+device when program is created with 'clCreateProgramWithBinary' or it can be the
+executable binary generated by 'clBuildProgram'. If program is created with
+'clCreateProgramWithSource', the binary returned is the binary generated by
+'clBuildProgram'. The bits returned can be an implementation-specific
+intermediate representation (a.k.a. IR) or device specific executable bits or
+both. The decision on which information is returned in the binary is up to the
+OpenCL implementation.
+
+To find out which device the program binary in the array refers to, use the
+'clGetProgramDevices' query to get the list of devices. There is a one-to-one
+correspondence between the array of data returned by 'clGetProgramBinaries' and
+array of devices returned by 'clGetProgramDevices'.  
+-}
+--clGetProgramBinaries :: CLProgram -> IO (Either CLError [[Word8]])
+clGetProgramBinaries prg = do
+  sval <- getProgramInfoSize prg infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right size -> allocaArray (numElems size) $ \(buff :: Ptr (Ptr Word8)) -> do
+      print sval
+      print buff
+      return . Left $ CL_SUCCESS
+    where 
+      infoid = getCLValue CL_PROGRAM_BINARIES
+      numElems s = (fromIntegral s) `div` elemSize
+      elemSize = sizeOf (nullPtr::Ptr Word8)
+{-
+CL_PROGRAM_BINARIES	Return type: unsigned char *[]
+Return the program binaries for all devices associated with program. For each device in program, the binary returned can be the binary specified for the device when program is created with clCreateProgramWithBinary or it can be the executable binary generated by clBuildProgram. If program is created with clCreateProgramWithSource, the binary returned is the binary generated by clBuildProgram. The bits returned can be an implementation-specific intermediate representation (a.k.a. IR) or device specific executable bits or both. The decision on which information is returned in the binary is up to the OpenCL implementation.
+
+param_value points to an array of n pointers where n is the number of devices associated with program. The buffer sizes needed to allocate the memory that these n pointers refer to can be queried using the CL_PROGRAM_BINARY_SIZES query as described in this table.
+
+Each entry in this array is used by the implementation as the location in memory where to copy the program binary for a specific device, if there is a binary available. To find out which device the program binary in the array refers to, use the CL_PROGRAM_DEVICES query to get the list of devices. There is a one-to-one correspondence between the array of n pointers returned by CL_PROGRAM_BINARIES and array of devices returned by CL_PROGRAM_DEVICES.
+-}
+
+-- -----------------------------------------------------------------------------
+#c
+enum CLProgramBuildInfo {
+  cL_PROGRAM_BUILD_STATUS=CL_PROGRAM_BUILD_STATUS,
+  cL_PROGRAM_BUILD_OPTIONS=CL_PROGRAM_BUILD_OPTIONS,
+  cL_PROGRAM_BUILD_LOG=CL_PROGRAM_BUILD_LOG,
+  };
+#endc
+{#enum CLProgramBuildInfo {upcaseFirstLetter} #}
+
+getProgramBuildInfoSize :: CLProgram -> CLDeviceID -> CLProgramInfo_ -> IO (Either CLError CSize)
+getProgramBuildInfoSize prg device infoid = alloca $ \(value_size :: Ptr CSize) -> do
+  errcode <- raw_clGetProgramBuildInfo prg device infoid 0 nullPtr value_size
+  if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+    then fmap Right $ peek value_size
+    else return . Left . toEnum . fromIntegral $ errcode
+  
+-- | Returns the build status of program for a specific device as given by
+-- device.
+clGetProgramBuildStatus :: CLProgram -> CLDeviceID -> IO (Either CLError CLBuildStatus)
+clGetProgramBuildStatus prg device = wrapGetInfo (\(dat :: Ptr CLBuildStatus_) 
+                                           -> raw_clGetProgramBuildInfo prg device infoid size (castPtr dat)) getEnumCL
+    where 
+      infoid = getCLValue CL_PROGRAM_BUILD_STATUS
+      size = fromIntegral $ sizeOf (0::CLBuildStatus_)
+
+-- | Return the build options specified by the options argument in
+-- clBuildProgram for device. If build status of program for device is
+-- 'CL_BUILD_NONE', an empty string is returned.
+clGetProgramBuildOptions :: CLProgram -> CLDeviceID -> IO (Either CLError String)
+clGetProgramBuildOptions prg device = do
+  sval <- getProgramBuildInfoSize prg device infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right n -> allocaArray (fromIntegral n) $ \(buff :: CString) -> do
+      errcode <- raw_clGetProgramBuildInfo prg device infoid n (castPtr buff) nullPtr
+      if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+        then fmap Right $ peekCString buff
+        else return . Left . toEnum . fromIntegral $ errcode
+    where 
+      infoid = getCLValue CL_PROGRAM_BUILD_OPTIONS
+  
+-- | Return the build log when 'clBuildProgram' was called for device. If build
+-- status of program for device is 'CL_BUILD_NONE', an empty string is returned.
+clGetProgramBuildLog :: CLProgram -> CLDeviceID -> IO (Either CLError String)
+clGetProgramBuildLog prg device = do
+  sval <- getProgramBuildInfoSize prg device infoid
+  case sval of
+    Left err -> return . Left $ err
+    Right n -> allocaArray (fromIntegral n) $ \(buff :: CString) -> do
+      errcode <- raw_clGetProgramBuildInfo prg device infoid n (castPtr buff) nullPtr
+      if errcode == (fromIntegral . fromEnum $ CL_SUCCESS)
+        then fmap Right $ peekCString buff
+        else return . Left . toEnum . fromIntegral $ errcode
+    where 
+      infoid = getCLValue CL_PROGRAM_BUILD_LOG
+  
+-- -----------------------------------------------------------------------------


This option is ignored for single precision numbers if the device does not
support single precision denormalized numbers i.e. 'CL_FP_DENORM' bit is not set
in 'CL_DEVICE_SINGLE_FP_CONFIG'.

This option is ignored for double precision numbers if the device does not
support double precision or if it does support double precison but
'CL_FP_DENORM' bit is not set in 'CL_DEVICE_DOUBLE_FP_CONFIG'.

This flag only applies for scalar and vector single precision floating-point
variables and computations on these floating-point variables inside a


 * 'CL_COMPILER_NOT_AVAILABLE' if program is created with
'clCreateProgramWithSource' and a compiler is not available
i.e. 'clGetDeviceCompilerAvailable' is set to 'False'.

 * 'CL_BUILD_PROGRAM_FAILURE' if there is a failure to build the program
executable. This error will be returned if 'clBuildProgram' does not return
