hgrib-0.3.0.0: src/Data/Grib/Raw/Value.chs
{- |
Module : Data.Grib.Raw.Value
Copyright : (c) Mattias Jakobsson 2015
License : GPL-3
Maintainer : mjakob422@gmail.com
Stability : unstable
Portability : portable
Access GRIB header and data values.
Most of the documentation herein was copied from the official
documentation of
<https://software.ecmwf.int/wiki/display/GRIB/Module+Index grib_api>.
-}
module Data.Grib.Raw.Value
( -- * Get values
gribGetLong
, gribGetDouble
, gribGetLongArray
, gribGetDoubleArray
, gribGetDoubleElement
, gribGetDoubleElements
, gribGetString
, gribGetBytes
, gribGetOffset
, gribGetSize
, gribGetLength
-- * Set values
, gribSetLong
, gribSetDouble
, gribSetLongArray
, gribSetDoubleArray
, gribSetString
, gribSetBytes
-- * Copy values
, gribCopyNamespace
) where
import Foreign ( Ptr, alloca, allocaArray, peek, peekArray, with
, withArrayLen )
import Foreign.C ( CDouble, CLong, CSize, CString, peekCStringLen, withCString )
{#import Data.Grib.Raw.Handle #}
import Data.Grib.Raw.Marshal
#include <grib_api.h>
{#typedef size_t CSize #}
-- int grib_get_offset(grib_handle* h, const char* key, size_t* offset);
--
-- |Get the number offset of a key in a message if several keys of
-- the same name are present, the offset of the last one is returned.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing.
{#fun unsafe grib_get_offset as ^ {
`GribHandle'
, withCString* `Key'
, alloca- `Int' peekIntegral*
} -> `()' checkStatus*- #}
-- int grib_get_size(grib_handle* h, const char* key, size_t* size);
--
-- |Get the number of coded value from a key, if several keys of the
-- same name are present, the total sum is returned.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing.
{#fun unsafe grib_get_size as ^ {
`GribHandle'
, withCString* `Key'
, alloca- `Int' peekIntegral*
} -> `()' checkStatus*- #}
-- int grib_get_length(grib_handle* h, const char* key, size_t *length);
--
-- |Get the length of the string representation of the key, if several
-- keys of the same name are present, the maximum length is returned.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing.
{#fun unsafe grib_get_length as ^ {
`GribHandle'
, withCString* `Key'
, alloca- `Int' peekIntegral*
} -> `()' checkStatus*- #}
-- int grib_get_long(grib_handle* h, const char* key, long* value);
--
-- |Get a long value from a key, if several keys of the same name are
-- present, the last one is returned.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing.
{#fun unsafe grib_get_long as ^ {
`GribHandle'
, withCString* `Key'
, alloca- `Int' peekIntegral*
} -> `()' checkStatus*- #}
-- int grib_get_double(grib_handle* h, const char* key, double* value);
--
-- |Get a double value from a key, if several keys of the same name
-- are present, the last one is returned.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing.
{#fun unsafe grib_get_double as ^ {
`GribHandle'
, withCString* `Key'
, alloca- `Double' peekReal*
} -> `()' checkStatus*- #}
-- int grib_get_double_element(grib_handle* h, const char* key, int i,
-- double* value);
--
-- There are no bounds check on i and a too large i often doesn't seem
-- to lead to a segmentation fault.
--
-- |Get as double the i-th element of the "key" array.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing.
--
-- __WARNING!__ There is no check if the index is out of bounds.
{#fun unsafe grib_get_double_element as ^ {
`GribHandle'
, withCString* `Key'
, `Int'
, alloca- `Double' peekReal*
} -> `()' checkStatus*- #}
-- int grib_get_double_elements(grib_handle* h, const char* key, int* i,
-- long size, double* value);
--
-- This function is not macro expanded since the length of the output
-- arguments depend on the length of the input arguments.
--
-- |Get as double array the elements of the "key" array whose indexes
-- are listed in the input array i.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing.
--
-- __WARNING!__ There is no check if the indices are out of bounds.
gribGetDoubleElements :: GribHandle -> Key -> [Int] -> IO [Double]
gribGetDoubleElements h key is =
withGribHandle h $ \h' ->
withCString key $ \key' ->
withArrayLen (map fromIntegral is) $ \n is' ->
allocaArray n $ \ds -> do
cCall h' key' is' (fromIntegral n) ds >>= checkStatus
fmap (map realToFrac) $ peekArray n ds
where cCall = {#call unsafe grib_get_double_elements #}
-- int grib_get_string(grib_handle* h, const char* key, char* mesg,
-- size_t *length);
--
-- This function is not macro expanded since an output marshaller
-- would want to return another data type than the corresponding input
-- marshaller accepts.
--
-- |Get a string value from a key, if several keys of the same name
-- are present, the last one is returned.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing; or
--
-- * @isGribException GribBufferTooSmall@ if the allocated string is
-- too small.
--
-- This function takes an allocated 'CString' and its length, which is
-- used to retrieve the string returned by the IO action. The
-- 'CString' is not automatically allocated by this function since it
-- could potentially be re-used between multiple calls and the length
-- is not known beforehand.
gribGetString :: GribHandle -- ^the handle to get the data from
-> Key -- ^the key to be searched
-> CString -- ^the address of a string where the
-- data will be retrieved
-> Int -- ^the allocated length of the string
-> IO String -- ^an IO action that will return the
-- string
gribGetString h key cs n =
withGribHandle h $ \h' ->
withCString key $ \key' ->
with (fromIntegral n) $ \n' -> do
cCall h' key' cs n' >>= checkStatus
fmap (fromIntegral . subtract 1) (peek n') >>= curry peekCStringLen cs
where cCall = {#call unsafe grib_get_string #}
-- int grib_get_bytes(grib_handle* h, const char* key, unsigned char* bytes,
-- size_t *length);
--
-- |Get raw bytes values from a key.
--
-- If several keys of the same name are present, the last one is
-- returned.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing; or
--
-- * @isGribException GribArrayTooSmall@ if the allocated array is
-- too small.
{#fun unsafe grib_get_bytes as ^ {
`GribHandle'
-- ^the handle to get the data from
, withCString* `Key'
-- ^the key to be searched
, id `Bytes' id
-- ^the address of a byte array where the data will be retrieved
, withIntegral* `Int' peekIntegral*
-- ^the allocated length of the byte array
} -> `()' checkStatus*-
-- ^an IO action that will return the address of the byte array
-- and the number of bytes retrieved
#}
-- int grib_get_double_array(grib_handle* h, const char* key, double* vals,
-- size_t *length);
--
-- This function is not macro expanded since an output marshaller
-- would want to return another data type than the corresponding input
-- marshaller accepts.
--
-- |Get double array values from a key.
--
-- If several keys of the same name are present, the last one is
-- returned.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing; or
--
-- * @isGribException GribArrayTooSmall@ if the allocated array is
-- too small.
--
-- This function takes an allocated array and its length, which is
-- used to retrieve the list returned by the IO action. The array is
-- not automatically allocated by this function since it could
-- potentially be re-used between multiple calls and the length is not
-- known beforehand.
gribGetDoubleArray :: GribHandle -- ^the handle to get the data from
-> Key -- ^the key to be searched
-> Ptr CDouble -- ^the address of a double array
-- where the data will be retrieved
-> Int -- ^the allocated length of the double
-- array
-> IO [Double] -- ^an IO action that will return the
-- data in a list
gribGetDoubleArray h key ds n = withGribHandle h $ \h' ->
fmap (map realToFrac) $ getArray (cCall h') key ds n
where cCall = {#call unsafe grib_get_double_array #}
-- int grib_get_long_array(grib_handle* h, const char* key, long* vals,
-- size_t *length);
--
-- This function is not macro expanded since an output marshaller
-- would want to return another data type than the corresponding input
-- marshaller accepts.
--
-- |Get long array values from a key.
--
-- If several keys of the same name are present, the last one is
-- returned.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing; or
--
-- * @isGribException GribArrayTooSmall@ if the allocated array is
-- too small.
--
-- This function takes an allocated array and its length, which is
-- used to retrieve the list returned by the IO action. The array is
-- not automatically allocated by this function since it could
-- potentially be re-used between multiple calls and the length is not
-- known beforehand.
gribGetLongArray :: GribHandle -- ^the handle to get the data from
-> Key -- ^the key to be searched
-> Ptr CLong -- ^the address of a long array where
-- the data will be retrieved
-> Int -- ^the allocated length of the long
-- array
-> IO [Int] -- ^an IO action that will return the
-- data in a list
gribGetLongArray h key ls n = withGribHandle h $ \h' ->
fmap (map fromIntegral) $ getArray (cCall h') key ls n
where cCall = {#call unsafe grib_get_long_array #}
-- int grib_copy_namespace(grib_handle* dest, const char* name,
-- grib_handle* src);
--
-- |Copy the keys belonging to a given namespace from a source handle
-- to a destination handle.
--
-- This operation may fail with:
--
-- * @isGribException GribNotImplemented@.
{#fun unsafe grib_copy_namespace as ^ {
`GribHandle' -- ^destination handle
, maybeWithCString* `Maybe String' -- ^namespace (pass @Nothing@
-- to copy all keys)
, `GribHandle' -- ^source handle
} -> `()' checkStatus*- -- ^an IO action that will
-- copy the keys
#}
-- int grib_set_long(grib_handle* h, const char* key, long val);
--
-- |Set a long value from a key.
--
-- If several keys of the same name are present, the last one is set.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing; or
--
-- * @isGribException GribReadOnly@ if the key is read-only.
{#fun unsafe grib_set_long as ^ {
`GribHandle'
, withCString* `Key'
, `Int'
} -> `()' checkStatus*- #}
-- int grib_set_double(grib_handle* h, const char* key, double val);
--
-- |Set a double value from a key.
--
-- If several keys of the same name are present, the last one is set.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing; or
--
-- * @isGribException GribReadOnly@ if the key is read-only.
{#fun unsafe grib_set_double as ^ {
`GribHandle'
, withCString* `Key'
, `Double'
} -> `()' checkStatus*- #}
-- int grib_set_string(grib_handle* h, const char* key, const char* mesg,
-- size_t *length);
--
-- This function is not macro expanded since an output marshaller
-- would want to return another data type than the corresponding input
-- marshaller accepts.
--
-- |Set a string value from a key and return the actual packed length.
--
-- If several keys of the same name are present, the last one is set.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing; or
--
-- * @isGribException GribReadOnly@ if the key is read-only.
gribSetString :: GribHandle -> Key -> String -> IO Int
gribSetString h key msg =
withGribHandle h $ \h' ->
withCString key $ \key' ->
withCString msg $ \msg' ->
with (fromIntegral $ length msg) $ \n -> do
cCall h' key' msg' n >>= checkStatus
fmap fromIntegral $ peek n
where cCall = {#call unsafe grib_set_string #}
-- int grib_set_bytes(grib_handle* h, const char* key,
-- const unsigned char* bytes, size_t *length);
--
-- |Set a bytes array from a key and return the actual packed length.
--
-- If several keys of the same name are present, the last one is set.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing.
{#fun unsafe grib_set_bytes as ^ {
`GribHandle'
, withCString* `Key'
, id `Bytes'
, withIntegral* `Int' peekIntegral*
} -> `()' checkStatus*- #}
-- int grib_set_double_array(grib_handle* h, const char* key,
-- const double* vals, size_t length);
--
-- |Set a double array from a key.
--
-- If several keys of the same name are present, the last one is set.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing; or
--
-- * @isGribException GribReadOnly@ if the key is read-only.
--
-- __WARNING!__ Strange things seem to happen if an empty list is
-- passed in.
{#fun unsafe grib_set_double_array as ^ {
`GribHandle'
, withCString* `Key'
, withRealArrayLen* `[Double]'&
} -> `()' checkStatus*- #}
-- int grib_set_long_array(grib_handle* h, const char* key, const long* vals,
-- size_t length);
--
-- |Set a long array from a key.
--
-- If several keys of the same name are present, the last one is set.
--
-- This operation may fail with:
--
-- * @isGribException GribNotFound@ if the key is missing; or
--
-- * @isGribException GribReadOnly@ if the key is read-only.
{#fun unsafe grib_set_long_array as ^ {
`GribHandle'
, withCString* `Key'
, withIntegralArrayLen* `[Int]'&
} -> `()' checkStatus*- #}