1 {-# OPTIONS -fno-implicit-prelude #-}
2 -----------------------------------------------------------------------------
4 -- Module : Foreign.C.String
5 -- Copyright : (c) The FFI task force 2001
6 -- License : BSD-style (see the file libraries/base/LICENSE)
8 -- Maintainer : ffi@haskell.org
9 -- Stability : provisional
10 -- Portability : portable
12 -- Utilities for primitive marshaling
14 -----------------------------------------------------------------------------
16 module Foreign.C.String ( -- representation of strings in C
18 CString, -- = Ptr CChar
19 CStringLen, -- = (CString, Int)
21 -- conversion of C strings into Haskell strings
23 peekCString, -- :: CString -> IO String
24 peekCStringLen, -- :: CStringLen -> IO String
26 -- conversion of Haskell strings into C strings
28 newCString, -- :: String -> IO CString
29 newCStringLen, -- :: String -> IO CStringLen
31 -- conversion of Haskell strings into C strings using temporary storage
33 withCString, -- :: String -> (CString -> IO a) -> IO a
34 withCStringLen, -- :: String -> (CStringLen -> IO a) -> IO a
36 -- conversion between Haskell and C characters *ignoring* the encoding
38 castCharToCChar, -- :: Char -> CChar
39 castCCharToChar, -- :: CChar -> Char
43 import Foreign.Marshal.Array
44 import Foreign.C.Types
46 import Foreign.Storable
50 #ifdef __GLASGOW_HASKELL__
57 import Data.Char ( chr, ord )
61 -----------------------------------------------------------------------------
64 -- representation of strings in C
65 -- ------------------------------
67 type CString = Ptr CChar -- conventional NUL terminates strings
68 type CStringLen = (CString, Int) -- strings with explicit length
74 -- * the following routines apply the default conversion when converting the
75 -- C-land character encoding into the Haskell-land character encoding
77 -- ** NOTE: The current implementation doesn't handle conversions yet! **
79 -- * the routines using an explicit length tolerate NUL characters in the
83 -- marshal a NUL terminated C string into a Haskell string
85 peekCString :: CString -> IO String
86 #ifndef __GLASGOW_HASKELL__
87 peekCString cp = do cs <- peekArray0 nUL cp; return (cCharsToChars cs)
89 peekCString cp = loop 0
92 val <- peekElemOff cp i
93 if val == nUL then return [] else do
95 return (castCCharToChar val : rest)
98 -- marshal a C string with explicit length into a Haskell string
100 peekCStringLen :: CStringLen -> IO String
101 #ifndef __GLASGOW_HASKELL__
102 peekCStringLen (cp, len) = do cs <- peekArray len cp; return (cCharsToChars cs)
104 peekCStringLen (cp, len) = loop 0
106 loop i | i == len = return []
108 val <- peekElemOff cp i
110 return (castCCharToChar val : rest)
113 -- marshal a Haskell string into a NUL terminated C strings
115 -- * the Haskell string may *not* contain any NUL characters
117 -- * new storage is allocated for the C string and must be explicitly freed
119 newCString :: String -> IO CString
120 #ifndef __GLASGOW_HASKELL__
121 newCString = newArray0 nUL . charsToCChars
124 ptr <- mallocArray0 (length str)
126 go [] n# = pokeElemOff ptr (I# n#) nUL
127 go (c:cs) n# = do pokeElemOff ptr (I# n#) (castCharToCChar c); go cs (n# +# 1#)
132 -- marshal a Haskell string into a C string (ie, character array) with
133 -- explicit length information
135 -- * new storage is allocated for the C string and must be explicitly freed
137 newCStringLen :: String -> IO CStringLen
138 #ifndef __GLASGOW_HASKELL__
139 newCStringLen str = do a <- newArray (charsToCChars str)
140 return (pairLength str a)
142 newCStringLen str = do
143 ptr <- mallocArray0 len
146 go (c:cs) n# = do pokeElemOff ptr (I# n#) (castCharToCChar c); go cs (n# +# 1#)
153 -- marshal a Haskell string into a NUL terminated C strings using temporary
156 -- * the Haskell string may *not* contain any NUL characters
158 -- * see the lifetime constraints of `MarshalAlloc.alloca'
160 withCString :: String -> (CString -> IO a) -> IO a
161 #ifndef __GLASGOW_HASKELL__
162 withCString = withArray0 nUL . charsToCChars
165 allocaArray0 (length str) $ \ptr ->
167 go [] n# = pokeElemOff ptr (I# n#) nUL
168 go (c:cs) n# = do pokeElemOff ptr (I# n#) (castCharToCChar c); go cs (n# +# 1#)
174 -- marshal a Haskell string into a NUL terminated C strings using temporary
177 -- * the Haskell string may *not* contain any NUL characters
179 -- * see the lifetime constraints of `MarshalAlloc.alloca'
181 withCStringLen :: String -> (CStringLen -> IO a) -> IO a
182 #ifndef __GLASGOW_HASKELL__
183 withCStringLen str act = withArray (charsToCChars str) $ act . pairLength str
185 withCStringLen str f =
186 allocaArray len $ \ptr ->
189 go (c:cs) n# = do pokeElemOff ptr (I# n#) (castCharToCChar c); go cs (n# +# 1#)
197 -- auxilliary definitions
198 -- ----------------------
200 -- C's end of string character
205 -- pair a C string with the length of the given Haskell string
207 pairLength :: String -> CString -> CStringLen
208 pairLength = flip (,) . length
210 -- cast [CChar] to [Char]
212 cCharsToChars :: [CChar] -> [Char]
213 cCharsToChars xs = map castCCharToChar xs
215 -- cast [Char] to [CChar]
217 charsToCChars :: [Char] -> [CChar]
218 charsToCChars xs = map castCharToCChar xs
220 castCCharToChar :: CChar -> Char
221 castCCharToChar ch = unsafeChr (fromIntegral (fromIntegral ch :: Word8))
223 castCharToCChar :: Char -> CChar
224 castCharToCChar ch = fromIntegral (ord ch)