module System.Console.Isocline(
readline,
readlineEx,
setHistory,
historyClear,
historyRemoveLast,
historyAdd,
CompletionEnv,
completeFileName,
completeWord,
completeQuotedWord,
completeQuotedWordEx,
Completion(..),
completion,
isPrefix,
completionsFor,
wordCompleter,
highlightFmt,
Style, Fmt,
style,
plain,
pre,
putFmt,
putFmtLn,
styleDef,
styleOpen,
styleClose,
withStyle,
setPromptMarker,
enableAutoTab,
enableColor,
enableBeep,
enableMultiline,
enableHistoryDuplicates,
enableCompletionPreview,
enableMultilineIndent,
enableHighlight,
enableInlineHelp,
enableHint,
setHintDelay,
enableBraceMatching,
enableBraceInsertion,
setMatchingBraces,
setInsertionBraces,
setDefaultCompleter,
addCompletion,
addCompletionPrim,
addCompletions,
completeWordPrim,
completeQuotedWordPrim,
completeQuotedWordPrimEx,
readlineMaybe,
readlineExMaybe,
readlinePrim,
readlinePrimMaybe,
getPromptMarker,
getContinuationPromptMarker,
stopCompleting,
hasCompletions,
asyncStop,
HighlightEnv,
setDefaultHighlighter,
setDefaultFmtHighlighter,
termInit,
termDone,
withTerm,
termFlush,
termWrite,
termWriteLn,
termColor,
termBgColor,
termColorAnsi,
termBgColorAnsi,
termUnderline,
termReverse,
termReset
) where
import Data.List( intersperse, isPrefixOf )
import Control.Monad( when, foldM )
import Control.Exception( bracket )
import Foreign.C.String( CString, peekCString, peekCStringLen, withCString, castCharToCChar )
import Foreign.Ptr
import Foreign.C.Types
import qualified Data.ByteString as B ( useAsCString, packCString )
import qualified Data.Text as T ( pack, unpack )
import Data.Text.Encoding as TE ( decodeUtf8With, encodeUtf8)
import Data.Text.Encoding.Error ( lenientDecode )
data IcCompletionEnv
newtype CompletionEnv = CompletionEnv (Ptr IcCompletionEnv)
type CCompleterFun = Ptr IcCompletionEnv -> CString -> IO ()
type CompleterFun = CompletionEnv -> String -> IO ()
data IcHighlightEnv
newtype HighlightEnv = HighlightEnv (Ptr IcHighlightEnv)
type CHighlightFun = Ptr IcHighlightEnv -> CString -> Ptr () -> IO ()
type HighlightFun = HighlightEnv -> String -> IO ()
foreign import ccall ic_free :: (Ptr a) -> IO ()
foreign import ccall ic_malloc :: CSize -> IO (Ptr a)
foreign import ccall ic_strdup :: CString -> IO CString
foreign import ccall ic_readline :: CString -> IO CString
foreign import ccall ic_readline_ex :: CString -> FunPtr CCompleterFun -> (Ptr ()) -> FunPtr CHighlightFun -> (Ptr ()) -> IO CString
foreign import ccall ic_async_stop :: IO CCBool
unmaybe :: IO (Maybe String) -> IO String
unmaybe action
= do mb <- action
case mb of
Nothing -> return ""
Just s -> return s
readline :: String -> IO String
readline prompt
= unmaybe $ readlineMaybe prompt
readlineMaybe:: String -> IO (Maybe String)
readlineMaybe prompt
= withUTF8String prompt $ \cprompt ->
do cres <- ic_readline cprompt
res <- peekUTF8StringMaybe cres
ic_free cres
return res
readlineEx :: String -> Maybe (CompletionEnv -> String -> IO ()) -> Maybe (String -> Fmt) -> IO String
readlineEx prompt completer highlighter
= unmaybe $ readlineExMaybe prompt completer highlighter
readlineExMaybe :: String -> Maybe (CompletionEnv -> String -> IO ()) -> Maybe (String -> Fmt) -> IO (Maybe String)
readlineExMaybe prompt completer mbhighlighter
= readlinePrimMaybe prompt completer (case mbhighlighter of
Nothing -> Nothing
Just hl -> Just (highlightFmt hl))
readlinePrim :: String -> Maybe (CompletionEnv -> String -> IO ()) -> Maybe (HighlightEnv -> String -> IO ()) -> IO String
readlinePrim prompt completer highlighter
= unmaybe $ readlinePrimMaybe prompt completer highlighter
readlinePrimMaybe :: String -> Maybe (CompletionEnv -> String -> IO ()) -> Maybe (HighlightEnv -> String -> IO ()) -> IO (Maybe String)
readlinePrimMaybe prompt completer highlighter
= withUTF8String prompt $ \cprompt ->
do ccompleter <- makeCCompleter completer
chighlighter <- makeCHighlighter highlighter
cres <- ic_readline_ex cprompt ccompleter nullPtr chighlighter nullPtr
res <- peekUTF8StringMaybe cres
ic_free cres
when (ccompleter /= nullFunPtr) $ freeHaskellFunPtr ccompleter
when (chighlighter /= nullFunPtr) $ freeHaskellFunPtr chighlighter
return res
asyncStop :: IO Bool
asyncStop
= uncbool $ ic_async_stop
foreign import ccall ic_set_history :: CString -> CInt -> IO ()
foreign import ccall ic_history_remove_last :: IO ()
foreign import ccall ic_history_clear :: IO ()
foreign import ccall ic_history_add :: CString -> IO ()
setHistory :: FilePath -> Int -> IO ()
setHistory fname maxEntries
= withUTF8String0 fname $ \cfname ->
do ic_set_history cfname (toEnum maxEntries)
historyRemoveLast :: IO ()
historyRemoveLast
= ic_history_remove_last
historyClear :: IO ()
historyClear
= ic_history_clear
historyAdd :: String -> IO ()
historyAdd entry
= withUTF8String0 entry $ \centry ->
do ic_history_add centry
type CCBool = CInt
type CCharClassFun = CString -> CLong -> IO CCBool
type CharClassFun = Char -> Bool
foreign import ccall ic_set_default_completer :: FunPtr CCompleterFun -> IO ()
foreign import ccall "wrapper" ic_make_completer :: CCompleterFun -> IO (FunPtr CCompleterFun)
foreign import ccall "wrapper" ic_make_charclassfun :: CCharClassFun -> IO (FunPtr CCharClassFun)
foreign import ccall ic_add_completion_ex :: Ptr IcCompletionEnv -> CString -> CString -> CString -> IO CCBool
foreign import ccall ic_add_completion_prim :: Ptr IcCompletionEnv -> CString -> CString -> CString -> CInt -> CInt -> IO CCBool
foreign import ccall ic_complete_filename :: Ptr IcCompletionEnv -> CString -> CChar -> CString -> CString -> IO ()
foreign import ccall ic_complete_word :: Ptr IcCompletionEnv -> CString -> FunPtr CCompleterFun -> FunPtr CCharClassFun -> IO ()
foreign import ccall ic_complete_qword :: Ptr IcCompletionEnv -> CString -> FunPtr CCompleterFun -> FunPtr CCharClassFun -> IO ()
foreign import ccall ic_complete_qword_ex :: Ptr IcCompletionEnv -> CString -> FunPtr CCompleterFun -> FunPtr CCharClassFun -> CChar -> CString -> IO ()
foreign import ccall ic_has_completions :: Ptr IcCompletionEnv -> IO CCBool
foreign import ccall ic_stop_completing :: Ptr IcCompletionEnv -> IO CCBool
data Completion = Completion {
replacement :: String,
display :: String,
help :: String
}
completion :: String -> Completion
completion replacement
= Completion replacement "" ""
completionFull :: String -> String -> String -> Completion
completionFull replacement display help
= Completion replacement display help
isPrefix :: String -> Completion -> Bool
isPrefix input compl
= isPrefixOf input (replacement compl)
completionsFor :: String -> [String] -> [Completion]
completionsFor input rs
= map completion (filter (isPrefixOf input) rs)
wordCompleter :: [String] -> (CompletionEnv -> String -> IO ())
wordCompleter completions
= (\cenv input -> completeWord cenv input Nothing (\input -> completionsFor input completions))
setDefaultCompleter :: (CompletionEnv -> String -> IO ()) -> IO ()
setDefaultCompleter completer
= do ccompleter <- makeCCompleter (Just completer)
ic_set_default_completer ccompleter
withCCompleter :: Maybe CompleterFun -> (FunPtr CCompleterFun -> IO a) -> IO a
withCCompleter completer action
= bracket (makeCCompleter completer) (\cfun -> when (nullFunPtr /= cfun) (freeHaskellFunPtr cfun)) action
makeCCompleter :: Maybe CompleterFun -> IO (FunPtr CCompleterFun)
makeCCompleter Nothing = return nullFunPtr
makeCCompleter (Just completer)
= ic_make_completer wrapper
where
wrapper :: Ptr IcCompletionEnv -> CString -> IO ()
wrapper rpcomp cprefx
= do prefx <- peekUTF8String0 cprefx
completer (CompletionEnv rpcomp) prefx
addCompletion :: CompletionEnv -> Completion -> IO Bool
addCompletion (CompletionEnv rpc) (Completion replacement display help)
= withUTF8String replacement $ \crepl ->
withUTF8String0 display $ \cdisplay ->
withUTF8String0 help $ \chelp ->
do cbool <- ic_add_completion_ex rpc crepl cdisplay chelp
return (fromEnum cbool /= 0)
addCompletionPrim :: CompletionEnv -> Completion -> Int -> Int -> IO Bool
addCompletionPrim (CompletionEnv rpc) (Completion replacement display help) deleteBefore deleteAfter
= withUTF8String replacement $ \crepl ->
withUTF8String0 display $ \cdisplay ->
withUTF8String0 help $ \chelp ->
do cbool <- ic_add_completion_prim rpc crepl cdisplay chelp (toEnum deleteBefore) (toEnum deleteAfter)
return (fromEnum cbool /= 0)
addCompletions :: CompletionEnv -> [Completion] -> IO Bool
addCompletions compl [] = return True
addCompletions compl (c:cs)
= do continue <- addCompletion compl c
if (continue)
then addCompletions compl cs
else return False
completeFileName :: CompletionEnv -> String -> Maybe Char -> [FilePath] -> [String] -> IO ()
completeFileName (CompletionEnv rpc) prefx dirSep roots extensions
= withUTF8String prefx $ \cprefx ->
withUTF8String0 (concat (intersperse ";" roots)) $ \croots ->
withUTF8String0 (concat (intersperse ";" extensions)) $ \cextensions ->
do let cdirSep = case dirSep of
Nothing -> toEnum 0
Just c -> castCharToCChar c
ic_complete_filename rpc cprefx cdirSep croots cextensions
completeWord :: CompletionEnv -> String -> Maybe (Char -> Bool) -> (String -> [Completion]) -> IO ()
completeWord cenv input isWordChar completer
= completeWordPrim cenv input isWordChar cenvCompleter
where
cenvCompleter cenv input
= do addCompletions cenv (completer input)
return ()
completeQuotedWord :: CompletionEnv -> String -> Maybe (Char -> Bool) -> (String -> [Completion]) -> IO ()
completeQuotedWord cenv input isWordChar completer
= completeWordPrim cenv input isWordChar cenvCompleter
where
cenvCompleter cenv input
= do addCompletions cenv (completer input)
return ()
completeQuotedWordEx :: CompletionEnv -> String -> Maybe (Char -> Bool) -> Maybe Char -> String -> (String -> [Completion]) -> IO ()
completeQuotedWordEx cenv input isWordChar escapeChar quoteChars completer
= completeQuotedWordPrimEx cenv input isWordChar escapeChar quoteChars cenvCompleter
where
cenvCompleter cenv input
= do addCompletions cenv (completer input)
return ()
completeWordPrim :: CompletionEnv -> String -> Maybe (Char -> Bool) -> (CompletionEnv -> String -> IO ()) -> IO ()
completeWordPrim (CompletionEnv rpc) prefx isWordChar completer
= withUTF8String prefx $ \cprefx ->
withCharClassFun isWordChar $ \cisWordChar ->
withCCompleter (Just completer) $ \ccompleter ->
do ic_complete_word rpc cprefx ccompleter cisWordChar
completeQuotedWordPrim :: CompletionEnv -> String -> Maybe (Char -> Bool) -> (CompletionEnv -> String -> IO ()) -> IO ()
completeQuotedWordPrim (CompletionEnv rpc) prefx isWordChar completer
= withUTF8String prefx $ \cprefx ->
withCharClassFun isWordChar $ \cisWordChar ->
withCCompleter (Just completer) $ \ccompleter ->
do ic_complete_qword rpc cprefx ccompleter cisWordChar
completeQuotedWordPrimEx :: CompletionEnv -> String -> Maybe (Char -> Bool) -> Maybe Char -> String -> (CompletionEnv -> String -> IO ()) -> IO ()
completeQuotedWordPrimEx (CompletionEnv rpc) prefx isWordChar escapeChar quoteChars completer
= withUTF8String prefx $ \cprefx ->
withUTF8String0 quoteChars $ \cquoteChars ->
withCharClassFun isWordChar $ \cisWordChar ->
withCCompleter (Just completer) $ \ccompleter ->
do let cescapeChar = case escapeChar of
Nothing -> toEnum 0
Just c -> castCharToCChar c
ic_complete_qword_ex rpc cprefx ccompleter cisWordChar cescapeChar cquoteChars
withCharClassFun :: Maybe (Char -> Bool) -> (FunPtr CCharClassFun -> IO a) -> IO a
withCharClassFun isInClass action
= bracket (makeCharClassFun isInClass) (\cfun -> when (nullFunPtr /= cfun) (freeHaskellFunPtr cfun)) action
makeCharClassFun :: Maybe (Char -> Bool) -> IO (FunPtr CCharClassFun)
makeCharClassFun Nothing = return nullFunPtr
makeCharClassFun (Just isInClass)
= let charClassFun :: CString -> CLong -> IO CCBool
charClassFun cstr clen
= let len = (fromIntegral clen :: Int)
in if (len <= 0) then return (cbool False)
else do s <- peekCStringLen (cstr,len)
return (if null s then (cbool False) else cbool (isInClass (head s)))
in do ic_make_charclassfun charClassFun
stopCompleting :: CompletionEnv -> IO Bool
stopCompleting (CompletionEnv rpc)
= uncbool $ ic_stop_completing rpc
hasCompletions :: CompletionEnv -> IO Bool
hasCompletions (CompletionEnv rpc)
= uncbool $ ic_has_completions rpc
foreign import ccall ic_set_default_highlighter :: FunPtr CHighlightFun -> Ptr () -> IO ()
foreign import ccall "wrapper" ic_make_highlight_fun:: CHighlightFun -> IO (FunPtr CHighlightFun)
foreign import ccall ic_highlight :: Ptr IcHighlightEnv -> CLong -> CLong -> CString -> IO ()
foreign import ccall ic_highlight_formatted :: Ptr IcHighlightEnv -> CString -> CString -> IO ()
setDefaultHighlighter :: (HighlightEnv -> String -> IO ()) -> IO ()
setDefaultHighlighter highlighter
= do chighlighter <- makeCHighlighter (Just highlighter)
ic_set_default_highlighter chighlighter nullPtr
makeCHighlighter :: Maybe (HighlightEnv -> String -> IO ()) -> IO (FunPtr CHighlightFun)
makeCHighlighter Nothing = return nullFunPtr
makeCHighlighter (Just highlighter)
= ic_make_highlight_fun wrapper
where
wrapper :: Ptr IcHighlightEnv -> CString -> Ptr () -> IO ()
wrapper henv cinput carg
= do input <- peekUTF8String0 cinput
highlighter (HighlightEnv henv) input
highlight :: HighlightEnv -> Int -> Int -> String -> IO ()
highlight (HighlightEnv henv) pos len style
= withUTF8String0 style $ \cstyle ->
do ic_highlight henv (clong (-pos)) (clong (-len)) cstyle
type Style = String
type Fmt = String
highlightFmt :: (String -> Fmt) -> (HighlightEnv -> String -> IO ())
highlightFmt highlight (HighlightEnv henv) input
= withUTF8String0 input $ \cinput ->
withUTF8String0 (highlight input) $ \cfmt ->
do ic_highlight_formatted henv cinput cfmt
style :: Style -> Fmt -> Fmt
style st s
= if null st then s else ("[" ++ st ++ "]" ++ s ++ "[/]")
plain :: String -> Fmt
plain s
= if (any (\c -> (c == '[' || c == ']')) s) then "[!pre]" ++ s ++ "[/pre]" else s
pre :: Style -> String -> Fmt
pre st s
= style st (plain s)
setDefaultFmtHighlighter :: (String -> Fmt) -> IO ()
setDefaultFmtHighlighter highlight
= setDefaultHighlighter (highlightFmt highlight)
foreign import ccall ic_print :: CString -> IO ()
foreign import ccall ic_println :: CString -> IO ()
foreign import ccall ic_style_def :: CString -> CString -> IO ()
foreign import ccall ic_style_open :: CString -> IO ()
foreign import ccall ic_style_close :: IO ()
putFmt :: Fmt -> IO ()
putFmt s
= withUTF8String0 s $ \cs ->
do ic_print cs
putFmtLn :: Fmt -> IO ()
putFmtLn s
= withUTF8String0 s $ \cs ->
do ic_println cs
styleDef :: String -> Style -> IO ()
styleDef name style
= withUTF8String0 name $ \cname ->
withUTF8String0 style $ \cstyle ->
do ic_style_def cname cstyle
styleOpen :: Style -> IO ()
styleOpen style
= withUTF8String0 style $ \cstyle ->
do ic_style_open cstyle
styleClose :: IO ()
styleClose
= ic_style_close
withStyle :: Style -> IO a -> IO a
withStyle style action
= bracket (styleOpen style) (\() -> styleClose) (\() -> action)
foreign import ccall ic_term_init :: IO ()
foreign import ccall ic_term_done :: IO ()
foreign import ccall ic_term_flush :: IO ()
foreign import ccall ic_term_write :: CString -> IO ()
foreign import ccall ic_term_writeln :: CString -> IO ()
foreign import ccall ic_term_underline :: CCBool -> IO ()
foreign import ccall ic_term_reverse :: CCBool -> IO ()
foreign import ccall ic_term_color_ansi :: CCBool -> CInt -> IO ()
foreign import ccall ic_term_color_rgb :: CCBool -> CInt -> IO ()
foreign import ccall ic_term_style :: CString -> IO ()
foreign import ccall ic_term_reset :: IO ()
termInit :: IO ()
termInit
= ic_term_init
termDone :: IO ()
termDone
= ic_term_done
withTerm :: IO a -> IO a
withTerm action
= bracket termInit (\() -> termDone) (\() -> action)
termFlush :: IO ()
termFlush
= ic_term_flush
termWrite :: String -> IO ()
termWrite s
= withUTF8String0 s $ \cs -> ic_term_write cs
termWriteLn :: String -> IO ()
termWriteLn s
= withUTF8String0 s $ \cs -> ic_term_writeln cs
termColor :: Int -> IO ()
termColor color
= ic_term_color_rgb (cbool True) (toEnum color)
termBgColor :: Int -> IO ()
termBgColor color
= ic_term_color_rgb (cbool False) (toEnum color)
termColorAnsi :: Int -> IO ()
termColorAnsi color
= ic_term_color_ansi (cbool True) (toEnum color)
termBgColorAnsi :: Int -> IO ()
termBgColorAnsi color
= ic_term_color_ansi (cbool False) (toEnum color)
termStyle :: Style -> IO ()
termStyle style
= withUTF8String0 style $ \cstyle ->
do ic_term_style cstyle
termUnderline :: Bool -> IO ()
termUnderline enable
= ic_term_underline (cbool enable)
termReverse :: Bool -> IO ()
termReverse enable
= ic_term_reverse (cbool enable)
termReset :: IO ()
termReset
= ic_term_reset
foreign import ccall ic_set_prompt_marker :: CString -> CString -> IO ()
foreign import ccall ic_get_prompt_marker :: IO CString
foreign import ccall ic_get_continuation_prompt_marker :: IO CString
foreign import ccall ic_enable_multiline :: CCBool -> IO CCBool
foreign import ccall ic_enable_beep :: CCBool -> IO CCBool
foreign import ccall ic_enable_color :: CCBool -> IO CCBool
foreign import ccall ic_enable_auto_tab :: CCBool -> IO CCBool
foreign import ccall ic_enable_inline_help:: CCBool -> IO CCBool
foreign import ccall ic_enable_hint :: CCBool -> IO CCBool
foreign import ccall ic_set_hint_delay :: CLong -> IO CLong
foreign import ccall ic_enable_highlight :: CCBool -> IO CCBool
foreign import ccall ic_enable_history_duplicates :: CCBool -> IO CCBool
foreign import ccall ic_enable_completion_preview :: CCBool -> IO CCBool
foreign import ccall ic_enable_multiline_indent :: CCBool -> IO CCBool
foreign import ccall ic_enable_brace_matching :: CCBool -> IO CCBool
foreign import ccall ic_enable_brace_insertion :: CCBool -> IO CCBool
foreign import ccall ic_set_matching_braces :: CString -> IO ()
foreign import ccall ic_set_insertion_braces :: CString -> IO ()
cbool :: Bool -> CCBool
cbool True = toEnum 1
cbool False = toEnum 0
uncbool :: IO CCBool -> IO Bool
uncbool action
= do i <- action
return (i /= toEnum 0)
clong :: Int -> CLong
clong l = toEnum l
setPromptMarker :: String -> String -> IO ()
setPromptMarker marker multiline_marker
= withUTF8String0 marker $ \cmarker ->
withUTF8String0 multiline_marker $ \cmultiline_marker ->
do ic_set_prompt_marker cmarker cmultiline_marker
getPromptMarker :: IO String
getPromptMarker
= do cstr <- ic_get_prompt_marker
if (nullPtr == cstr)
then return ""
else do cstr2 <- ic_strdup cstr
peekUTF8String0 cstr2
getContinuationPromptMarker :: IO String
getContinuationPromptMarker
= do cstr <- ic_get_continuation_prompt_marker
if (nullPtr == cstr)
then return ""
else do cstr2 <- ic_strdup cstr
peekUTF8String0 cstr2
enableMultiline :: Bool -> IO Bool
enableMultiline enable
= do uncbool $ ic_enable_multiline (cbool enable)
enableBeep :: Bool -> IO Bool
enableBeep enable
= do uncbool $ ic_enable_beep (cbool enable)
enableColor :: Bool -> IO Bool
enableColor enable
= do uncbool $ ic_enable_color (cbool enable)
enableHistoryDuplicates :: Bool -> IO Bool
enableHistoryDuplicates enable
= do uncbool $ ic_enable_history_duplicates (cbool enable)
enableAutoTab :: Bool -> IO Bool
enableAutoTab enable
= do uncbool $ ic_enable_auto_tab (cbool enable)
enableInlineHelp :: Bool -> IO Bool
enableInlineHelp enable
= do uncbool $ ic_enable_inline_help (cbool enable)
enableCompletionPreview :: Bool -> IO Bool
enableCompletionPreview enable
= do uncbool $ ic_enable_completion_preview (cbool enable)
enableBraceMatching :: Bool -> IO Bool
enableBraceMatching enable
= do uncbool $ ic_enable_brace_matching (cbool enable)
enableBraceInsertion :: Bool -> IO Bool
enableBraceInsertion enable
= do uncbool $ ic_enable_brace_insertion (cbool enable)
setMatchingBraces :: String -> IO ()
setMatchingBraces bracePairs
= withUTF8String0 bracePairs $ \cbracePairs ->
do ic_set_matching_braces cbracePairs
setInsertionBraces :: String -> IO ()
setInsertionBraces bracePairs
= withUTF8String0 bracePairs $ \cbracePairs ->
do ic_set_insertion_braces cbracePairs
enableMultilineIndent :: Bool -> IO Bool
enableMultilineIndent enable
= do uncbool $ ic_enable_multiline_indent (cbool enable)
enableHint :: Bool -> IO Bool
enableHint enable
= do uncbool $ ic_enable_hint (cbool enable)
enableHighlight :: Bool -> IO Bool
enableHighlight enable
= do uncbool $ ic_enable_highlight (cbool enable)
setHintDelay :: Int -> IO Int
setHintDelay ms
= do cl <- ic_set_hint_delay (toEnum ms)
return (fromEnum cl)
withUTF8String0 :: String -> (CString -> IO a) -> IO a
withUTF8String0 s action
= if (null s) then action nullPtr else withUTF8String s action
peekUTF8String0 :: CString -> IO String
peekUTF8String0 cstr
= if (nullPtr == cstr) then return "" else peekUTF8String cstr
peekUTF8StringMaybe :: CString -> IO (Maybe String)
peekUTF8StringMaybe cstr
= if (nullPtr == cstr) then return Nothing
else do s <- peekUTF8String cstr
return (Just s)
peekUTF8String :: CString -> IO String
peekUTF8String cstr
= do bstr <- B.packCString cstr
return (T.unpack (TE.decodeUtf8With lenientDecode bstr))
withUTF8String :: String -> (CString -> IO a) -> IO a
withUTF8String str action
= do let bstr = TE.encodeUtf8 (T.pack str)
B.useAsCString bstr action