@@ -0,0 +1,310 @@
1+{-# LANGUAGE EmptyDataDecls #-}
2+{-# LANGUAGE ForeignFunctionInterface #-}
3+
4+{-# INCLUDE <yaml.h> #-}
5+{-# INCLUDE <helper.h> #-}
6+module Text.Libyaml
7+{-
8+ (
9+ Event (..)
10+ , parserParse
11+ , withParser
12+ , emitEvents
13+ , withEmitter
14+ )-} where
15+
16+import qualified Data.ByteString.Internal as B
17+import Control.Monad
18+import Foreign.C
19+import Foreign.Ptr
20+import Foreign.ForeignPtr
21+import Foreign.Marshal.Alloc
22+
23+data ParserStruct
24+type Parser = Ptr ParserStruct
25+parserSize :: Int
26+parserSize = 480
27+
28+data EventRawStruct
29+type EventRaw = Ptr EventRawStruct
30+eventSize :: Int
31+eventSize = 104
32+
33+foreign import ccall unsafe "yaml_parser_initialize"
34+ c_yaml_parser_initialize :: Parser -> IO CInt
35+
36+foreign import ccall unsafe "yaml_parser_delete"
37+ c_yaml_parser_delete :: Parser -> IO ()
38+
39+foreign import ccall unsafe "yaml_parser_set_input_string"
40+ c_yaml_parser_set_input_string :: Parser
41+ -> Ptr CUChar
42+ -> CULong
43+ -> IO ()
44+
45+withParser :: B.ByteString -> (Parser -> IO a) -> IO a
46+withParser bs f = do
47+ allocaBytes parserSize $ \p ->
48+ do
49+ _res <- c_yaml_parser_initialize p
50+ -- FIXME check res
51+ let (fptr, offset, len) = B.toForeignPtr bs
52+ ret <- withForeignPtr fptr $ \ptr ->
53+ do
54+ let ptr' = castPtr ptr `plusPtr` offset
55+ len' = fromIntegral len
56+ c_yaml_parser_set_input_string p ptr' len'
57+ f p
58+ c_yaml_parser_delete p
59+ return ret
60+
61+withEventRaw :: (EventRaw -> IO a) -> IO a
62+withEventRaw f = allocaBytes eventSize $ f
63+
64+foreign import ccall unsafe "yaml_parser_parse"
65+ c_yaml_parser_parse :: Parser -> EventRaw -> IO CInt
66+
67+foreign import ccall unsafe "yaml_event_delete"
68+ c_yaml_event_delete :: EventRaw -> IO ()
69+
70+foreign import ccall "print_parser_error"
71+ c_print_parser_error :: Parser -> IO ()
72+
73+parserParseOne :: Parser -> IO Event
74+parserParseOne parser = withEventRaw $ \er -> do
75+ res <- c_yaml_parser_parse parser er
76+ when (res == 0) $
77+ c_print_parser_error parser >> fail "yaml_parser_parse failed"
78+ event <- getEvent er
79+ c_yaml_event_delete er
80+ return event
81+
82+data Event =
83+ EventNone
84+ | EventStreamStart
85+ | EventStreamEnd
86+ | EventDocumentStart
87+ | EventDocumentEnd
88+ | EventAlias
89+ | EventScalar B.ByteString
90+ | EventSequenceStart
91+ | EventSequenceEnd
92+ | EventMappingStart
93+ | EventMappingEnd
94+ deriving (Show)
95+
96+data EventType = YamlNoEvent
97+ | YamlStreamStartEvent
98+ | YamlStreamEndEvent
99+ | YamlDocumentStartEvent
100+ | YamlDocumentEndEvent
101+ | YamlAliasEvent
102+ | YamlScalarEvent
103+ | YamlSequenceStartEvent
104+ | YamlSequenceEndEvent
105+ | YamlMappingStartEvent
106+ | YamlMappingEndEvent
107+ deriving (Enum,Show)
108+
109+foreign import ccall unsafe "get_event_type"
110+ c_get_event_type :: EventRaw -> IO CInt
111+
112+foreign import ccall unsafe "get_scalar_value"
113+ c_get_scalar_value :: EventRaw -> IO (Ptr CUChar)
114+
115+foreign import ccall unsafe "get_scalar_length"
116+ c_get_scalar_length :: EventRaw -> IO CULong
117+
118+getEvent :: EventRaw -> IO Event
119+getEvent er = do
120+ et <- c_get_event_type er
121+ case toEnum $ fromEnum et of
122+ YamlNoEvent -> return EventNone
123+ YamlStreamStartEvent -> return EventStreamStart
124+ YamlStreamEndEvent -> return EventStreamEnd
125+ YamlDocumentStartEvent -> return EventDocumentStart
126+ YamlDocumentEndEvent -> return EventDocumentEnd
127+ YamlAliasEvent -> return EventAlias
128+ YamlScalarEvent -> do
129+ yvalue <- c_get_scalar_value er
130+ ylen <- c_get_scalar_length er
131+ let yvalue' = castPtr yvalue
132+ let ylen' = fromEnum ylen
133+ let ylen'' = toEnum $ fromEnum ylen
134+ bs <- B.create ylen' $ \dest -> B.memcpy dest yvalue' ylen''
135+ return $ EventScalar bs
136+ YamlSequenceStartEvent -> return EventSequenceStart
137+ YamlSequenceEndEvent -> return EventSequenceEnd
138+ YamlMappingStartEvent -> return EventMappingStart
139+ YamlMappingEndEvent -> return EventMappingEnd
140+
141+parserParse :: Parser -> IO [Event]
142+parserParse parser = do
143+ event <- parserParseOne parser
144+ case event of
145+ EventStreamEnd -> return [event]
146+ _ -> do
147+ rest <- parserParse parser
148+ return $! event : rest
149+
150+-- Emitter
151+
152+data EmitterStruct
153+type Emitter = Ptr EmitterStruct
154+emitterSize :: Int
155+emitterSize = 432
156+
157+foreign import ccall unsafe "yaml_emitter_initialize"
158+ c_yaml_emitter_initialize :: Emitter -> IO CInt
159+
160+foreign import ccall unsafe "yaml_emitter_delete"
161+ c_yaml_emitter_delete :: Emitter -> IO ()
162+
163+data BufferStruct
164+type Buffer = Ptr BufferStruct
165+bufferSize :: Int
166+bufferSize = 16
167+
168+foreign import ccall unsafe "buffer_init"
169+ c_buffer_init :: Buffer -> IO ()
170+
171+foreign import ccall unsafe "get_buffer_buff"
172+ c_get_buffer_buff :: Buffer -> IO (Ptr CUChar)
173+
174+foreign import ccall unsafe "get_buffer_used"
175+ c_get_buffer_used :: Buffer -> IO CULong
176+
177+withBuffer :: (Buffer -> IO ()) -> IO B.ByteString
178+withBuffer f = do
179+ allocaBytes bufferSize $ \b -> do
180+ c_buffer_init b
181+ f b
182+ ptr' <- c_get_buffer_buff b
183+ len <- c_get_buffer_used b
184+ fptr <- newForeignPtr_ $ castPtr ptr'
185+ return $! B.fromForeignPtr fptr 0 $ fromIntegral len
186+
187+foreign import ccall unsafe "my_emitter_set_output"
188+ c_my_emitter_set_output :: Emitter -> Buffer -> IO ()
189+
190+withEmitter :: (Emitter -> IO ()) -> IO B.ByteString
191+withEmitter f = do
192+ allocaBytes emitterSize $ \e -> do
193+ _res <- c_yaml_emitter_initialize e
194+ -- FIXME check res
195+ bs <- withBuffer $ \b -> do
196+ c_my_emitter_set_output e b
197+ f e
198+ c_yaml_emitter_delete e
199+ return bs
200+
201+foreign import ccall unsafe "yaml_emitter_emit"
202+ c_yaml_emitter_emit :: Emitter -> EventRaw -> IO CInt
203+
204+foreign import ccall unsafe "print_emitter_error"
205+ c_print_emitter_error :: Emitter -> IO ()
206+
207+emitEvents :: Emitter -> [Event] -> IO ()
208+emitEvents _ [] = return ()
209+emitEvents emitter (e:rest) = do
210+ res <- toEventRaw e $ c_yaml_emitter_emit emitter
211+ when (res == 0) $
212+ c_print_emitter_error emitter >> fail "yaml_emitter_emit failed"
213+ emitEvents emitter rest
214+
215+foreign import ccall unsafe "yaml_stream_start_event_initialize"
216+ c_yaml_stream_start_event_initialize :: EventRaw -> CInt -> IO CInt
217+
218+foreign import ccall unsafe "yaml_stream_end_event_initialize"
219+ c_yaml_stream_end_event_initialize :: EventRaw -> IO CInt
220+
221+foreign import ccall unsafe "yaml_scalar_event_initialize"
222+ c_yaml_scalar_event_initialize
223+ :: EventRaw
224+ -> Ptr CUChar -- anchor
225+ -> Ptr CUChar -- tag
226+ -> Ptr CUChar -- value
227+ -> CInt
228+ -> CInt
229+ -> CInt
230+ -> CInt
231+ -> IO CInt
232+
233+foreign import ccall unsafe "simple_document_start"
234+ c_simple_document_start :: EventRaw -> IO CInt
235+
236+foreign import ccall unsafe "yaml_document_end_event_initialize"
237+ c_yaml_document_end_event_initialize :: EventRaw -> CInt -> IO CInt
238+
239+foreign import ccall unsafe "yaml_sequence_start_event_initialize"
240+ c_yaml_sequence_start_event_initialize
241+ :: EventRaw
242+ -> Ptr CUChar
243+ -> Ptr CUChar
244+ -> CInt
245+ -> CInt
246+ -> IO CInt
247+
248+foreign import ccall unsafe "yaml_sequence_end_event_initialize"
249+ c_yaml_sequence_end_event_initialize :: EventRaw -> IO CInt
250+
251+foreign import ccall unsafe "yaml_mapping_start_event_initialize"
252+ c_yaml_mapping_start_event_initialize
253+ :: EventRaw
254+ -> Ptr CUChar
255+ -> Ptr CUChar
256+ -> CInt
257+ -> CInt
258+ -> IO CInt
259+
260+foreign import ccall unsafe "yaml_mapping_end_event_initialize"
261+ c_yaml_mapping_end_event_initialize :: EventRaw -> IO CInt
262+
263+toEventRaw :: Event -> (EventRaw -> IO a) -> IO a
264+toEventRaw e f = withEventRaw $ \er -> do
265+ case e of
266+ EventStreamStart ->
267+ c_yaml_stream_start_event_initialize
268+ er
269+ 0 -- YAML_ANY_ENCODING
270+ EventStreamEnd ->
271+ c_yaml_stream_end_event_initialize er
272+ EventDocumentStart ->
273+ c_simple_document_start er
274+ EventDocumentEnd ->
275+ c_yaml_document_end_event_initialize er 1
276+ EventScalar bs -> do
277+ let (fvalue, offset, len) = B.toForeignPtr bs
278+ withForeignPtr fvalue $ \value -> do
279+ let value' = value `plusPtr` offset
280+ len' = fromIntegral len
281+ c_yaml_scalar_event_initialize
282+ er
283+ nullPtr
284+ nullPtr
285+ value'
286+ len'
287+ 0
288+ 1
289+ 0 -- YAML_ANY_SCALAR_STYLE
290+ EventSequenceStart ->
291+ c_yaml_sequence_start_event_initialize
292+ er
293+ nullPtr
294+ nullPtr
295+ 1
296+ 0 -- YAML_ANY_SEQUENCE_STYLE
297+ EventSequenceEnd ->
298+ c_yaml_sequence_end_event_initialize er
299+ EventMappingStart ->
300+ c_yaml_mapping_start_event_initialize
301+ er
302+ nullPtr
303+ nullPtr
304+ 1
305+ 0 -- YAML_ANY_SEQUENCE_STYLE
306+ EventMappingEnd ->
307+ c_yaml_mapping_end_event_initialize er
308+ EventAlias -> error "toEventRaw: EventAlias not supported"
309+ EventNone -> error "toEventRaw: EventNone not supported"
310+ f er