[project @ 2003-01-28 11:09:41 by simonmar]
[ghc-base.git] / Foreign / C / String.hs
1 {-# OPTIONS -fno-implicit-prelude #-}
2 -----------------------------------------------------------------------------
3 -- |
4 -- Module      :  Foreign.C.String
5 -- Copyright   :  (c) The FFI task force 2001
6 -- License     :  BSD-style (see the file libraries/base/LICENSE)
7 -- 
8 -- Maintainer  :  ffi@haskell.org
9 -- Stability   :  provisional
10 -- Portability :  portable
11 --
12 -- Utilities for primitive marshaling
13 --
14 -----------------------------------------------------------------------------
15
16 module Foreign.C.String (   -- representation of strings in C
17
18   CString,           -- = Ptr CChar
19   CStringLen,        -- = (CString, Int)
20
21   -- conversion of C strings into Haskell strings
22   --
23   peekCString,       -- :: CString    -> IO String
24   peekCStringLen,    -- :: CStringLen -> IO String
25
26   -- conversion of Haskell strings into C strings
27   --
28   newCString,        -- :: String -> IO CString
29   newCStringLen,     -- :: String -> IO CStringLen
30
31   -- conversion of Haskell strings into C strings using temporary storage
32   --
33   withCString,       -- :: String -> (CString    -> IO a) -> IO a
34   withCStringLen,    -- :: String -> (CStringLen -> IO a) -> IO a
35
36   -- conversion between Haskell and C characters *ignoring* the encoding
37   --
38   castCharToCChar,   -- :: Char -> CChar
39   castCCharToChar,   -- :: CChar -> Char
40
41   ) where
42
43 import Foreign.Marshal.Array
44 import Foreign.C.Types
45 import Foreign.Ptr
46 import Foreign.Storable
47
48 import Data.Word
49
50 #ifdef __GLASGOW_HASKELL__
51 import GHC.List
52 import GHC.Real
53 import GHC.Num
54 import GHC.IOBase
55 import GHC.Base
56 #else
57 import Char ( chr, ord )
58 #define unsafeChr chr
59 #endif
60
61 -----------------------------------------------------------------------------
62 -- Strings
63
64 -- representation of strings in C
65 -- ------------------------------
66
67 type CString    = Ptr CChar             -- conventional NUL terminates strings
68 type CStringLen = (CString, Int)        -- strings with explicit length
69
70
71 -- exported functions
72 -- ------------------
73 --
74 -- * the following routines apply the default conversion when converting the
75 --   C-land character encoding into the Haskell-land character encoding
76 --
77 --   ** NOTE: The current implementation doesn't handle conversions yet! **
78 --
79 -- * the routines using an explicit length tolerate NUL characters in the
80 --   middle of a string
81 --
82
83 -- marshal a NUL terminated C string into a Haskell string 
84 --
85 peekCString    :: CString -> IO String
86 #ifndef __GLASGOW_HASKELL__
87 peekCString cp  = do cs <- peekArray0 nUL cp; return (cCharsToChars cs)
88 #else
89 peekCString cp = loop 0
90   where
91     loop i = do
92         val <- peekElemOff cp i
93         if val == nUL then return [] else do
94             rest <- loop (i+1)
95             return (castCCharToChar val : rest)
96 #endif
97
98 -- marshal a C string with explicit length into a Haskell string 
99 --
100 peekCStringLen           :: CStringLen -> IO String
101 #ifndef __GLASGOW_HASKELL__
102 peekCStringLen (cp, len)  = do cs <- peekArray len cp; return (cCharsToChars cs)
103 #else
104 peekCStringLen (cp, len) = loop 0
105   where
106     loop i | i == len  = return []
107            | otherwise = do
108                 val <- peekElemOff cp i
109                 rest <- loop (i+1)
110                 return (castCCharToChar val : rest)
111 #endif
112
113 -- marshal a Haskell string into a NUL terminated C strings
114 --
115 -- * the Haskell string may *not* contain any NUL characters
116 --
117 -- * new storage is allocated for the C string and must be explicitly freed
118 --
119 newCString :: String -> IO CString
120 #ifndef __GLASGOW_HASKELL__
121 newCString  = newArray0 nUL . charsToCChars
122 #else
123 newCString str = do
124   ptr <- mallocArray0 (length str)
125   let
126         go [] n#     = pokeElemOff ptr (I# n#) nUL
127         go (c:cs) n# = do pokeElemOff ptr (I# n#) (castCharToCChar c); go cs (n# +# 1#)
128   go str 0#
129   return ptr
130 #endif
131
132 -- marshal a Haskell string into a C string (ie, character array) with
133 -- explicit length information
134 --
135 -- * new storage is allocated for the C string and must be explicitly freed
136 --
137 newCStringLen     :: String -> IO CStringLen
138 #ifndef __GLASGOW_HASKELL__
139 newCStringLen str  = do a <- newArray (charsToCChars str)
140                         return (pairLength str a)
141 #else
142 newCStringLen str = do
143   ptr <- mallocArray0 len
144   let
145         go [] n#     = return ()
146         go (c:cs) n# = do pokeElemOff ptr (I# n#) (castCharToCChar c); go cs (n# +# 1#)
147   go str 0#
148   return (ptr, len)
149   where
150     len = length str
151 #endif
152
153 -- marshal a Haskell string into a NUL terminated C strings using temporary
154 -- storage
155 --
156 -- * the Haskell string may *not* contain any NUL characters
157 --
158 -- * see the lifetime constraints of `MarshalAlloc.alloca'
159 --
160 withCString :: String -> (CString -> IO a) -> IO a
161 #ifndef __GLASGOW_HASKELL__
162 withCString  = withArray0 nUL . charsToCChars
163 #else
164 withCString str f =
165   allocaArray0 (length str) $ \ptr ->
166       let
167         go [] n#     = pokeElemOff ptr (I# n#) nUL
168         go (c:cs) n# = do pokeElemOff ptr (I# n#) (castCharToCChar c); go cs (n# +# 1#)
169       in do
170       go str 0#
171       f ptr
172 #endif
173
174 -- marshal a Haskell string into a NUL terminated C strings using temporary
175 -- storage
176 --
177 -- * the Haskell string may *not* contain any NUL characters
178 --
179 -- * see the lifetime constraints of `MarshalAlloc.alloca'
180 --
181 withCStringLen         :: String -> (CStringLen -> IO a) -> IO a
182 #ifndef __GLASGOW_HASKELL__
183 withCStringLen str act  = withArray (charsToCChars str) $ act . pairLength str
184 #else
185 withCStringLen str f =
186   allocaArray len $ \ptr ->
187       let
188         go [] n#     = return ()
189         go (c:cs) n# = do pokeElemOff ptr (I# n#) (castCharToCChar c); go cs (n# +# 1#)
190       in do
191       go str 0#
192       f (ptr,len)
193   where
194     len = length str
195 #endif
196
197 -- auxilliary definitions
198 -- ----------------------
199
200 -- C's end of string character
201 --
202 nUL :: CChar
203 nUL  = 0
204
205 -- pair a C string with the length of the given Haskell string
206 --
207 pairLength :: String -> CString -> CStringLen
208 pairLength  = flip (,) . length
209
210 -- cast [CChar] to [Char]
211 --
212 cCharsToChars :: [CChar] -> [Char]
213 cCharsToChars xs  = map castCCharToChar xs
214
215 -- cast [Char] to [CChar]
216 --
217 charsToCChars :: [Char] -> [CChar]
218 charsToCChars xs  = map castCharToCChar xs
219
220 castCCharToChar :: CChar -> Char
221 castCCharToChar ch = unsafeChr (fromIntegral (fromIntegral ch :: Word8))
222
223 castCharToCChar :: Char -> CChar
224 castCharToCChar ch = fromIntegral (ord ch)