{-# LINE 1 "System/Console/Readline.hsc" #-}
{-# OPTIONS -fglasgow-exts #-}
{-# LINE 2 "System/Console/Readline.hsc" #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  System.Console.Readline
-- Copyright   :  (c) unknown
-- License     :  GPL (depends on libreadline, which is GPL)
-- 
-- Maintainer  :  libraries@haskell.org
-- Stability   :  provisional
-- Portability :  non-portable (requires libreadline)
--
-- A Haskell binding to the GNU readline library.  The GNU Readline
-- library provides a set of functions for use by applications that
-- allow users to edit command lines as they are typed in.  By
-- default, the line editing commands are similar to those of
-- emacs.  A vi-style line editing interface is also available.
--
-- An example of a typical use of readline with history functionality
-- is illustrated in the following read, eval, print loop:
--
-- @
-- readEvalPrintLoop :: IO ()
-- readEvalPrintLoop = do
--   maybeLine <- readline \"% \"
--   case maybeLine of 
--    Nothing     -> return () -- EOF \/ control-d
--    Just \"exit\" -> return ()
--    Just line -> do addHistory line
--                    putStrLn $ \"The user input: \" ++ (show line)
--                    readEvalPrintLoop
-- @
--

-----------------------------------------------------------------------------


{-# LINE 37 "System/Console/Readline.hsc" #-}

{-# LINE 38 "System/Console/Readline.hsc" #-}
module System.Console.Readline (
    --------------------------------------------------------------------
    -- Basic Behavior.
    
    readline,   -- :: String -> IO (Maybe String)
    addHistory, -- :: String -> IO ()
    
    --------------------------------------------------------------------
    -- Readline Variables.
    
    getLineBuffer,        -- :: IO String

{-# LINE 50 "System/Console/Readline.hsc" #-}
    setLineBuffer,        -- :: String -> IO ()

{-# LINE 52 "System/Console/Readline.hsc" #-}
    
    -- Functions involving point positions are meaningful only when string
    -- conversion between Haskell and C preserves the length.
    getPoint,             -- :: IO Int
    setPoint,             -- :: Int -> IO ()
    getEnd,               -- :: IO Int
    setEnd,               -- :: Int -> IO ()
    getMark,              -- :: IO Int
    setMark,              -- :: Int -> IO ()
    
    setDone,              -- :: Bool -> IO ()
    setPendingInput,      -- :: Char -> IO ()

{-# LINE 65 "System/Console/Readline.hsc" #-}
    setEraseEmptyLine,    -- :: Bool -> IO ()

{-# LINE 67 "System/Console/Readline.hsc" #-}
    getPrompt,            -- :: IO String

{-# LINE 69 "System/Console/Readline.hsc" #-}
    setAlreadyPrompted,   -- :: Bool -> IO ()

{-# LINE 71 "System/Console/Readline.hsc" #-}
    getLibraryVersion,    -- :: IO String
    getTerminalName,      -- :: IO String
    setReadlineName,      -- :: String -> IO ()
    getInStream,          -- :: IO Handle
    getOutStream,         -- :: IO Handle
    setStartupHook,       -- :: Maybe (IO ()) -> IO ()

{-# LINE 78 "System/Console/Readline.hsc" #-}
    setPreInputHook,      -- :: Maybe (IO ()) -> IO ()

{-# LINE 80 "System/Console/Readline.hsc" #-}
    setEventHook,         -- :: Maybe (IO ()) -> IO ()
    -- rl_getc_function wrapper is not provided because it uses FILE *
    -- and it would be too expensive to convert FILE * to Handle
    -- for each character.
    setRedisplayFunction, -- :: Maybe (IO ()) -> IO ()
    -- Nothing means the original: rl_redisplay.
    
    --------------------------------------------------------------------
    -- Selecting a Keymap.
    
    -- Keymaps are not garbage collected. They must be explicitly freed
    -- using freeKeymap.
    
    Keymap,             -- data Keymap
    newBareKeymap,      -- :: IO Keymap
    copyKeymap,         -- :: Keymap -> IO Keymap
    newKeymap,          -- :: IO Keymap
    freeKeymap,         -- :: Keymap -> IO ()
    getKeymap,          -- :: IO Keymap
    setKeymap,          -- :: Keymap -> IO ()
    getKeymapByName,    -- :: String -> IO Keymap
    getKeymapName,      -- :: Keymap -> IO (Maybe String)
    getExecutingKeymap, -- :: IO Keymap
    getBindingKeymap,   -- :: IO Keymap
    
    --------------------------------------------------------------------
    -- Binding Keys.
    
    Callback,           -- type Callback = Int -> Char -> IO Int
    addDefun,           -- :: String -> Callback -> Maybe Char -> IO ()
    bindKey,            -- :: Char -> Callback -> IO ()
    bindKeyInMap,       -- :: Char -> Callback -> Keymap -> IO ()
    unbindKey,          -- :: Char -> IO ()
    unbindKeyInMap,     -- :: Char -> Keymap -> IO ()
    -- rl_unbind_function_in_map is not provided because Haskell functions
    -- have no identity.
    unbindCommandInMap, -- :: String -> Keymap -> IO ()
    Entry(..),          -- data Entry
                        --     = Function Callback
                        --     | Macro    String
                        --     | Keymap   Keymap
    genericBind,        -- :: String -> Entry -> Keymap -> IO ()
    parseAndBind,       -- :: String -> IO ()
    readInitFile,       -- :: String -> IO ()
    
    --------------------------------------------------------------------
    -- Associating Function Names and Bindings.
    
    namedFunction,    -- :: String -> IO (Maybe Callback)
    functionOfKeyseq, -- :: String -> Maybe Keymap -> IO Entry
    -- rl_invoking_keyseqs and rl_invoking_keyseqs_in_map are not provided
    -- because Haskell functions have no identity.
    functionDumper,   -- :: Bool -> IO ()
    listFunmapNames,  -- :: IO ()

{-# LINE 135 "System/Console/Readline.hsc" #-}
    funmapNames,      -- :: IO [String]

{-# LINE 137 "System/Console/Readline.hsc" #-}
    
    --------------------------------------------------------------------
    -- Allowing Undoing.
    
    beginUndoGroup, endUndoGroup, -- :: IO ()
    UndoCode(..),   -- data UndoCode
                    --     = UndoDelete
                    --     | UndoInsert
                    --     | UndoBegin
                    --     | UndoEnd
    addUndo,        -- :: UndoCode -> Int -> Int -> String -> IO ()
    freeUndoList,   -- :: IO ()
    doUndo,         -- :: IO Bool
    modifying,      -- :: Int -> Int -> IO ()
    
    --------------------------------------------------------------------
    -- Redisplay.
    
    redisplay,                      -- :: IO ()
    forcedUpdateDisplay,            -- :: IO ()
    onNewLine,                      -- :: IO ()

{-# LINE 159 "System/Console/Readline.hsc" #-}
    onNewLineWithPrompt,            -- :: IO ()

{-# LINE 161 "System/Console/Readline.hsc" #-}
    resetLineState,                 -- :: IO ()
    message,                        -- :: String -> IO ()
    clearMessage,                   -- :: IO ()

{-# LINE 165 "System/Console/Readline.hsc" #-}
    savePrompt,                     -- :: IO ()
    restorePrompt,                  -- :: IO ()

{-# LINE 168 "System/Console/Readline.hsc" #-}

    --------------------------------------------------------------------
    -- Modifying Text.
    
    insertText, -- :: String -> IO ()
    deleteText, -- :: Int -> Int -> IO ()
    copyText,   -- :: Int -> Int -> IO String
    killText,   -- :: Int -> Int -> IO ()
    
    --------------------------------------------------------------------
    -- Utility functions.
    
    readKey,          -- :: IO Char
    stuffChar,        -- :: Char -> IO Bool
    initialize,       -- :: IO ()
    resetTerminal,    -- :: Maybe String -> IO ()
    ding,             -- :: IO Bool

{-# LINE 186 "System/Console/Readline.hsc" #-}
    displayMatchList, -- :: [String] -> IO ()

{-# LINE 188 "System/Console/Readline.hsc" #-}
    
    --------------------------------------------------------------------
    -- Alternate Interface.
    
    callbackHandlerInstall, -- :: String -> (String -> IO ()) -> IO (IO ())
    -- Returns the cleanup action.
    callbackReadChar,       -- :: IO ()
    
    --------------------------------------------------------------------
    -- Readline Signal Handling.
    

{-# LINE 200 "System/Console/Readline.hsc" #-}
    setCatchSignals,    -- :: Bool -> IO ()
    getCatchSignals,    -- :: IO Bool
    setCatchSigwinch,   -- :: Bool -> IO ()
    getCatchSigwinch,   -- :: IO Bool
    cleanupAfterSignal, -- :: IO ()
    freeLineState,      -- :: IO ()
    resetAfterSignal,   -- :: IO ()
    resizeTerminal,     -- :: IO ()

{-# LINE 209 "System/Console/Readline.hsc" #-}
    setSignals,         -- :: IO ()
    clearSignals,       -- :: IO ()
    
    --------------------------------------------------------------------
    -- Completion functions.
    
    completeInternal,                 -- :: Char -> IO ()
    complete,                         -- :: Int -> Char -> IO Int
    possibleCompletions,              -- :: Int -> Char -> IO Int
    insertCompletions,                -- :: Int -> Char -> IO Int
    -- readline uses functions that are called multiple times and
    -- return an entry at a time, maintaining their state at which
    -- point they are. This is silly in a functional language so here
    -- we work with functions String -> IO [String].
    completionMatches,
        -- :: String -> (String -> IO [String]) -> IO (Maybe (String, [String]))
    filenameCompletionFunction,       -- :: String -> IO [String]
    usernameCompletionFunction,       -- :: String -> IO [String]
    setCompletionEntryFunction,
        -- :: Maybe (String -> IO [String]) -> IO ()
    setAttemptedCompletionFunction,
        -- :: Maybe (String -> Int -> Int -> IO (Maybe (String, [String]))) -> IO ()
    setFilenameQuotingFunction,
        -- :: Maybe (String -> Bool -> Ptr CChar -> IO String) -> IO ()
    quoteFilename,
        -- :: String -> Bool -> Ptr CChar -> IO String
    setFilenameDequotingFunction,
        -- :: Maybe (String -> Maybe Char -> IO String) -> IO ()
    setCharIsQuotedP,
        -- :: Maybe (String -> Int -> IO Bool) -> IO ()
    getCompletionQueryItems,          -- :: IO Int
    setCompletionQueryItems,          -- :: Int -> IO ()
    getBasicWordBreakCharacters,      -- :: IO String
    setBasicWordBreakCharacters,      -- :: String -> IO ()
    getBasicQuoteCharacters,          -- :: IO String
    setBasicQuoteCharacters,          -- :: String -> IO ()
    getCompleterWordBreakCharacters,  -- :: IO String
    setCompleterWordBreakCharacters,  -- :: String -> IO ()
    getCompleterQuoteCharacters,      -- :: IO String
    setCompleterQuoteCharacters,      -- :: String -> IO ()
    getFilenameQuoteCharacters,       -- :: IO String
    setFilenameQuoteCharacters,       -- :: String -> IO ()
    getSpecialPrefixes,               -- :: IO String
    setSpecialPrefixes,               -- :: String -> IO ()
    getCompletionAppendCharacter,     -- :: IO (Maybe Char)
    setCompletionAppendCharacter,     -- :: Maybe Char -> IO ()
    setIgnoreCompletionDuplicates,    -- :: Bool -> IO ()
    getIgnoreCompletionDuplicates,    -- :: IO Bool
    setFilenameCompletionDesired,     -- :: Bool -> IO ()
    getFilenameCompletionDesired,     -- :: IO Bool
    setFilenameQuotingDesired,        -- :: Bool -> IO ()
    getFilenameQuotingDesired,        -- :: IO Bool
    setInhibitCompletion,             -- :: Bool -> IO ()
    getInhibitCompletion,             -- :: IO Bool
    setAttemptedCompletionOver,       -- :: Bool -> IO ()
    getAttemptedCompletionOver,       -- :: IO Bool
    setIgnoreSomeCompletionsFunction,
        -- :: Maybe ([String] -> IO [String]) -> IO ()
        -- The function may not make the list longer!
    setDirectoryCompletionHook
        -- :: Maybe (String -> IO String) -> IO ()

{-# LINE 271 "System/Console/Readline.hsc" #-}
    ,
    setCompletionWordBreakHook
        -- :: Maybe (IO (Maybe String)) -> IO ()

{-# LINE 275 "System/Console/Readline.hsc" #-}

{-# LINE 276 "System/Console/Readline.hsc" #-}
    ,
    setCompletionDisplayMatchesHook
        -- :: Maybe ([String] -> IO ()) -> IO ()

{-# LINE 280 "System/Console/Readline.hsc" #-}
    )
    
    where

------------------------------------------------------------------------

import Control.Monad	( liftM, when, unless )
import Data.Char	( chr, ord )
import Data.Maybe	( fromMaybe )
import System.IO	( Handle )
import System.IO.Unsafe ( unsafePerformIO )
import Data.IORef	( newIORef, readIORef, writeIORef )
import Foreign.Ptr	( Ptr, nullPtr, castPtr, castFunPtrToPtr,
			  FunPtr, nullFunPtr, freeHaskellFunPtr )
import Foreign.Storable	( Storable(..) )
import Foreign.Marshal.Utils ( maybePeek, maybeWith, withMany )
import Foreign.Marshal.Alloc ( alloca, free )
import Foreign.Marshal.Array ( mallocArray, peekArray0, pokeArray0, withArray0 )
import Foreign.C.Types	( CInt, CChar, CFile )
import Foreign.C.String	( newCString, peekCString, withCString,
			  castCharToCChar, castCCharToChar )
import GHC.Handle	( fdToHandle )

{-# CFILES HsReadline_cbits.c #-}

------------------------------------------------------------------------
-- Basic Behavior.

-- | readline is similar to 'System.IO.getLine', but with rich edit
-- functionality and history capability.  readline will read a line
-- from the terminal and return it, using /prompt/ as a prompt.  If
-- prompt is the empty string, no prompt is issued.  The line returned
-- has the final newline removed, so only the text of the line
-- remains.  A blank line returns the empty string.  If EOF is
-- encountered while reading a line, and the line is empty, Nothing is
-- returned.  If an EOF is read with a non-empty line, it is treated
-- as a newline.

readline :: String-- ^prompt
	 -> IO (Maybe String) -- ^returns the line the user input, or Nothing if EOF is encountered.
readline prompt = do
    ptr <- withCString prompt readlineC
    flip maybePeek ptr $ \ptr' -> do
        line <- peekCString ptr'
        free ptr'
        return line
foreign import ccall "readline" readlineC :: Ptr CChar -> IO (Ptr CChar)


-- |Add this command to the history.  This allows users to search backward
-- through history with C-r and step through with up and down arrows, among
-- other things.
addHistory :: String -> IO ()
addHistory line = withCString line add_history
foreign import ccall unsafe add_history :: Ptr CChar -> IO ()

------------------------------------------------------------------------
-- Readline Variables.

getLineBuffer :: IO String
getLineBuffer = peek rl_line_buffer >>= peekCString


{-# LINE 343 "System/Console/Readline.hsc" #-}
setLineBuffer :: String -> IO ()
setLineBuffer line = do
    -- TODO: Fix the next line when text conversions are available!
    let lineC = map castCharToCChar line
    rl_extend_line_buffer (fromIntegral (length lineC))
    ptr <- peek rl_line_buffer
    pokeArray0 0 (castPtr ptr) lineC

{-# LINE 351 "System/Console/Readline.hsc" #-}

foreign import ccall "&"
  rl_line_buffer :: Ptr (Ptr CChar)

{-# LINE 355 "System/Console/Readline.hsc" #-}
-- The readline docs claim that rl_extend_line_buffer returns CInt,
-- but the header and source both say that it returns void.
foreign import ccall unsafe rl_extend_line_buffer :: CInt -> IO ()

{-# LINE 359 "System/Console/Readline.hsc" #-}

-- Functions involving point positions are meaningful only when string
-- conversion between Haskell and C preserves the length.

getPoint :: IO Int
getPoint = liftM fromIntegral (peek rl_point)

setPoint :: Int -> IO ()
setPoint p = poke rl_point (fromIntegral p)

foreign import ccall "&" rl_point :: Ptr CInt

getEnd :: IO Int
getEnd = liftM fromIntegral (peek rl_end)

setEnd :: Int -> IO ()
setEnd p = poke rl_end (fromIntegral p)

foreign import ccall "&" rl_end :: Ptr CInt

getMark :: IO Int
getMark = liftM fromIntegral (peek rl_mark)

setMark :: Int -> IO ()
setMark p = poke rl_mark (fromIntegral p)

foreign import ccall "&" rl_mark :: Ptr CInt

setDone :: Bool -> IO ()
setDone done = poke rl_done (if done then 1 else 0)
foreign import ccall "&" rl_done :: Ptr CInt

setPendingInput :: Char -> IO ()
setPendingInput key = poke rl_pending_input (fromIntegral (ord key))
foreign import ccall "&" rl_pending_input :: Ptr CInt


{-# LINE 396 "System/Console/Readline.hsc" #-}
setEraseEmptyLine :: Bool -> IO ()
setEraseEmptyLine erase = poke rl_erase_empty_line (if erase then 1 else 0)
foreign import ccall "&" rl_erase_empty_line :: Ptr CInt

{-# LINE 400 "System/Console/Readline.hsc" #-}

getPrompt :: IO String
getPrompt = peek rl_prompt >>= peekCString
foreign import ccall "&" rl_prompt :: Ptr (Ptr CChar)


{-# LINE 406 "System/Console/Readline.hsc" #-}
setAlreadyPrompted :: Bool -> IO ()
setAlreadyPrompted pr = poke rl_already_prompted (if pr then 1 else 0)
foreign import ccall "&" rl_already_prompted :: Ptr CInt

{-# LINE 410 "System/Console/Readline.hsc" #-}

getLibraryVersion :: IO String
getLibraryVersion = peek rl_library_version >>= peekCString
foreign import ccall "&" rl_library_version :: Ptr (Ptr CChar)

getTerminalName :: IO String
getTerminalName = peek rl_terminal_name >>= peekCString
foreign import ccall "&" rl_terminal_name :: Ptr (Ptr CChar)

setReadlineName :: String -> IO ()
setReadlineName name = newCString name >>= poke rl_readline_name
    -- The memory for name will never be freed. Otherwise we would
    -- have to recognize the original value which is a static string
    -- literal. This function is usually called only once anyway.
foreign import ccall "&" rl_readline_name :: Ptr (Ptr CChar)

getInStream :: IO Handle
getInStream = peek rl_instream >>= hs_fileno >>= fdToHandle . fromIntegral
foreign import ccall "&" rl_instream :: Ptr (Ptr CFile)

getOutStream :: IO Handle
getOutStream = peek rl_outstream >>= hs_fileno >>= fdToHandle . fromIntegral
foreign import ccall "&" rl_outstream :: Ptr (Ptr CFile)

foreign import ccall unsafe "__hscore_hs_fileno"
  hs_fileno :: Ptr CFile -> IO CInt

setStartupHook :: Maybe (IO ()) -> IO ()
setStartupHook hook = setFunPtr rl_startup_hook hook exportHookInt
foreign import ccall "&" rl_startup_hook :: Ptr (FunPtr (IO CInt))


{-# LINE 442 "System/Console/Readline.hsc" #-}
setPreInputHook :: Maybe (IO ()) -> IO ()
setPreInputHook hook = setFunPtr rl_pre_input_hook hook exportHookInt
foreign import ccall "&" rl_pre_input_hook :: Ptr (FunPtr (IO CInt))

{-# LINE 446 "System/Console/Readline.hsc" #-}

setEventHook :: Maybe (IO ()) -> IO ()
setEventHook hook = setFunPtr rl_event_hook hook exportHookInt
foreign import ccall "&" rl_event_hook :: Ptr (FunPtr (IO CInt))

-- rl_getc_function wrapper is not provided because it uses FILE *
-- and it would be too expensive to convert FILE * to Handle
-- for each character.

setRedisplayFunction :: Maybe (IO ()) -> IO ()
-- Nothing means the original: rl_redisplay.
setRedisplayFunction fun = do
    oldPtr <- peek rl_redisplay_function
    when (oldPtr /= nullFunPtr && oldPtr /= rl_redisplay) $
        freeHaskellFunPtr oldPtr
    newPtr <- case fun of
        Nothing -> return rl_redisplay
        Just f  -> exportHookVoid f
    poke rl_redisplay_function newPtr
foreign import ccall "&" rl_redisplay_function :: Ptr (FunPtr (IO ()))
foreign import ccall "&" rl_redisplay :: FunPtr (IO ())
-- rl_redisplay_function can never be NULL.

exportHookInt :: IO () -> IO (FunPtr (IO CInt))
exportHookInt hook = exportHookIntC (hook >> return 0)
foreign import ccall "wrapper"
  exportHookIntC :: IO CInt -> IO (FunPtr (IO CInt))

foreign import ccall "wrapper"
  exportHookVoid :: IO () -> IO (FunPtr (IO ()))

setFunPtr_freeIf :: (FunPtr a -> Bool)
                 -> Ptr (FunPtr a)
                 -> Maybe b
                 -> (b -> IO (FunPtr a))
                 -> IO ()
setFunPtr_freeIf pred variable newFun makeNewFun = do
    oldPtr <- peek variable
    when (pred oldPtr) $ freeHaskellFunPtr oldPtr
    newPtr <- case newFun of
        Nothing -> return nullFunPtr
        Just f  -> makeNewFun f
    poke variable newPtr

setFunPtr :: Ptr (FunPtr a)
          -> Maybe b
          -> (b -> IO (FunPtr a))
          -> IO ()
setFunPtr = setFunPtr_freeIf (/= nullFunPtr)

------------------------------------------------------------------------
-- Selecting a Keymap.

-- Keymaps are not garbage collected. They must be explicitly freed
-- using freeKeymap.

data KeymapTag = KeymapTag
newtype Keymap = MkKeymap (Ptr KeymapTag)

foreign import ccall unsafe "rl_make_bare_keymap" newBareKeymap :: IO Keymap

foreign import ccall unsafe "rl_copy_keymap" copyKeymap :: Keymap -> IO Keymap

foreign import ccall unsafe "rl_make_keymap" newKeymap :: IO Keymap

freeKeymap :: Keymap -> IO ()
freeKeymap k@(MkKeymap km) = do
    rl_discard_keymap k
    free km

foreign import ccall unsafe "rl_discard_keymap" 
  rl_discard_keymap :: Keymap -> IO ()

foreign import ccall unsafe "rl_get_keymap"
  getKeymap :: IO Keymap

foreign import ccall unsafe "rl_set_keymap"
  setKeymap :: Keymap -> IO ()

getKeymapByName :: String -> IO Keymap
getKeymapByName name = withCString name rl_get_keymap_by_name
foreign import ccall unsafe 
  rl_get_keymap_by_name :: Ptr CChar -> IO Keymap

getKeymapName :: Keymap -> IO (Maybe String)
getKeymapName km = do
    ptr <- rl_get_keymap_name km
    maybePeek peekCString ptr

foreign import ccall unsafe "rl_get_keymap_name"
  rl_get_keymap_name :: Keymap -> IO (Ptr CChar)

getExecutingKeymap :: IO Keymap
getExecutingKeymap = liftM MkKeymap $ peek rl_executing_keymap
foreign import ccall "&" rl_executing_keymap :: Ptr (Ptr KeymapTag)

getBindingKeymap :: IO Keymap
getBindingKeymap = liftM MkKeymap $ peek rl_binding_keymap
foreign import ccall "&" rl_binding_keymap :: Ptr (Ptr KeymapTag)

------------------------------------------------------------------------
-- Binding Keys.

type Callback = Int -> Char -> IO Int
type CallbackC = CInt -> CInt -> IO CInt

addDefun :: String -> Callback -> Maybe Char -> IO ()
addDefun name cb key = do
    namePtr <- newCString name
    -- rl_add_defun does *not* make a copy of the function name.
    cbPtr <- exportCallback cb
    -- The memory will never be freed. But readline does not provide
    -- removing defuns anyway.
    rl_add_defun namePtr cbPtr (maybe (-1) (fromIntegral . ord) key)
    return ()
foreign import ccall unsafe "rl_add_defun"
    rl_add_defun :: Ptr CChar -> FunPtr CallbackC -> CInt -> IO CInt

bindKey :: Char -> Callback -> IO ()
bindKey key cb = do
    cbPtr <- exportCallback cb
    -- The memory will never be freed. We should provide a way to
    -- free it, but it's complicated because of multiple keymaps.
    -- It should probably be done explicitly.
    rl_bind_key (fromIntegral (ord key)) cbPtr
    return ()
foreign import ccall unsafe "rl_bind_key"
  rl_bind_key :: CInt -> FunPtr CallbackC -> IO CInt

bindKeyInMap :: Char -> Callback -> Keymap -> IO ()
bindKeyInMap key cb km = do
    cbPtr <- exportCallback cb
    rl_bind_key_in_map (fromIntegral (ord key)) cbPtr km
    return ()
foreign import ccall unsafe "rl_bind_key_in_map"
    rl_bind_key_in_map :: CInt -> FunPtr CallbackC -> Keymap -> IO CInt

unbindKey :: Char -> IO ()
unbindKey key = do
    rl_unbind_key (fromIntegral (ord key))
    return ()
foreign import ccall unsafe rl_unbind_key :: CInt -> IO CInt

unbindKeyInMap :: Char -> Keymap -> IO ()
unbindKeyInMap key km = do
    rl_unbind_key_in_map (fromIntegral (ord key)) km
    return ()
foreign import ccall unsafe "rl_unbind_key_in_map"
  rl_unbind_key_in_map :: CInt -> Keymap -> IO CInt

-- rl_unbind_function_in_map is not provided because Haskell functions
-- have no identity.

unbindCommandInMap :: String -> Keymap -> IO ()
unbindCommandInMap comm km = do
    withCString comm $ \commPtr -> rl_unbind_command_in_map commPtr km
    return ()
foreign import ccall unsafe "rl_unbind_command_in_map"
  rl_unbind_command_in_map :: Ptr CChar -> Keymap -> IO CInt

data Entry
    = Function Callback
    | Macro String
    | Keymap Keymap

genericBind :: String -> Entry -> Keymap -> IO ()
genericBind keys (Function cb) km = do
    cbPtr <- exportCallback cb
    genericBind' (0) keys (castFunPtrToPtr cbPtr) km
{-# LINE 615 "System/Console/Readline.hsc" #-}
genericBind keys (Macro s) km =
    withCString s $ \ptr -> genericBind' (2) keys ptr km
{-# LINE 617 "System/Console/Readline.hsc" #-}
genericBind keys (Keymap (MkKeymap km')) km =
    genericBind' (1) keys (castPtr km') km
{-# LINE 619 "System/Console/Readline.hsc" #-}

genericBind' :: CInt -> String -> Ptr CChar -> Keymap -> IO ()
genericBind' typ keys dat km = do
    withCString keys $ \keysPtr -> rl_generic_bind typ keysPtr dat km
    return ()
foreign import ccall unsafe "rl_generic_bind"
    rl_generic_bind :: CInt -> Ptr CChar -> Ptr CChar -> Keymap -> IO CInt

parseAndBind :: String -> IO ()
parseAndBind s = do
    ok <- withCString s rl_parse_and_bind
    unless (ok == 0) $ ioError (userError "Parse error")
foreign import ccall unsafe "rl_parse_and_bind"
  rl_parse_and_bind :: Ptr CChar -> IO CInt

readInitFile :: String -> IO ()
readInitFile name = do
    ok <- withCString name rl_read_init_file
    unless (ok == 0) $ ioError (userError "Can't read file")
foreign import ccall unsafe "rl_read_init_file"
  rl_read_init_file :: Ptr CChar -> IO CInt

------------------------------------------------------------------------
-- Associating Function Names and Bindings.

namedFunction :: String -> IO (Maybe Callback)
namedFunction name = do
    ptr <- withCString name rl_named_function
    return $ if ptr == nullFunPtr then Nothing else Just (importCallback ptr)
foreign import ccall unsafe "rl_named_function"
  rl_named_function :: Ptr CChar -> IO (FunPtr CallbackC)

functionOfKeyseq :: String -> Maybe Keymap -> IO Entry
functionOfKeyseq keys km =
    withCString keys $ \keysPtr -> alloca $ \typPtr -> do
        dat <- rl_function_of_keyseq keysPtr (fromMaybe (MkKeymap nullPtr) km) typPtr
        typ <- peek typPtr
        case typ of
            (0) ->
{-# LINE 658 "System/Console/Readline.hsc" #-}
                return (Function (importCallback dat))
            (2) ->
{-# LINE 660 "System/Console/Readline.hsc" #-}
                liftM Macro (peekCString (castFunPtrToPtr dat))
            (1) ->
{-# LINE 662 "System/Console/Readline.hsc" #-}
                return (Keymap (MkKeymap (castFunPtrToPtr dat)))
            _ -> error "functionOfKeyseq: unknown type"
foreign import ccall unsafe "rl_function_of_keyseq"
  rl_function_of_keyseq :: Ptr CChar -> Keymap -> Ptr CInt -> IO (FunPtr CallbackC)

-- rl_invoking_keyseqs and rl_invoking_keyseqs_in_map are not provided
-- because Haskell functions have no identity.

functionDumper :: Bool -> IO ()
functionDumper readable = rl_function_dumper (if readable then 1 else 0)
foreign import ccall unsafe "rl_function_dumper"
  rl_function_dumper :: CInt -> IO ()

foreign import ccall unsafe "rl_list_funmap_names" listFunmapNames :: IO ()


{-# LINE 678 "System/Console/Readline.hsc" #-}
funmapNames :: IO [String]
funmapNames = do
    namesPtr <- rl_funmap_names
    namePtrs <- peekArray0 nullPtr namesPtr
    free namesPtr
    mapM peekCString namePtrs
foreign import ccall unsafe "rl_funmap_names"
  rl_funmap_names :: IO (Ptr (Ptr CChar))

{-# LINE 687 "System/Console/Readline.hsc" #-}

exportCallback :: Callback -> IO (FunPtr CallbackC)
exportCallback cb =
    exportCallbackC $ \n key ->
        liftM fromIntegral (cb (fromIntegral n) (chr (fromIntegral key)))
foreign import ccall "wrapper" 
  exportCallbackC :: CallbackC -> IO (FunPtr CallbackC)

importCallback :: FunPtr CallbackC -> Callback
importCallback ptr n key =
    liftM fromIntegral $
        importCallbackC ptr (fromIntegral n) (fromIntegral (ord key))
foreign import ccall "dynamic"
  importCallbackC :: FunPtr CallbackC -> CallbackC

------------------------------------------------------------------------
-- Allowing Undoing.

beginUndoGroup :: IO ()
beginUndoGroup = do rl_begin_undo_group; return ()
foreign import ccall unsafe "rl_begin_undo_group"
  rl_begin_undo_group :: IO CInt

endUndoGroup :: IO ()
endUndoGroup = do rl_end_undo_group; return ()
foreign import ccall unsafe "rl_end_undo_group"
  rl_end_undo_group :: IO CInt

data UndoCode = UndoDelete | UndoInsert | UndoBegin | UndoEnd

addUndo :: UndoCode -> Int -> Int -> String -> IO ()
addUndo uc start end text =
    withCString text $ \textPtr ->
        rl_add_undo uc' (fromIntegral start) (fromIntegral end) textPtr
    where
    uc' = case uc of
        UndoDelete -> 0
{-# LINE 724 "System/Console/Readline.hsc" #-}
        UndoInsert -> 1
{-# LINE 725 "System/Console/Readline.hsc" #-}
        UndoBegin  -> 2
{-# LINE 726 "System/Console/Readline.hsc" #-}
        UndoEnd    -> 3
{-# LINE 727 "System/Console/Readline.hsc" #-}
foreign import ccall unsafe 
  rl_add_undo :: CInt -> CInt -> CInt -> Ptr CChar -> IO ()


{-# LINE 731 "System/Console/Readline.hsc" #-}
foreign import ccall unsafe "rl_free_undo_list" freeUndoList :: IO ()

{-# LINE 735 "System/Console/Readline.hsc" #-}

doUndo :: IO Bool
doUndo = liftM (/= 0) rl_do_undo
foreign import ccall unsafe "rl_do_undo"
  rl_do_undo :: IO CInt

modifying :: Int -> Int -> IO ()
modifying start end = do
    rl_modifying (fromIntegral start) (fromIntegral end)
    return ()
foreign import ccall unsafe "rl_modifying"
  rl_modifying :: CInt -> CInt -> IO CInt

------------------------------------------------------------------------
-- Redisplay.

foreign import ccall unsafe "rl_redisplay" redisplay :: IO ()

forcedUpdateDisplay :: IO ()
forcedUpdateDisplay = do rl_forced_update_display; return ()
foreign import ccall unsafe "rl_forced_update_display"
  rl_forced_update_display :: IO CInt

onNewLine :: IO ()
onNewLine = do rl_on_new_line; return ()
foreign import ccall unsafe "rl_on_new_line"
  rl_on_new_line :: IO CInt


{-# LINE 764 "System/Console/Readline.hsc" #-}
onNewLineWithPrompt :: IO ()
onNewLineWithPrompt = do rl_on_new_line_with_prompt; return ()
foreign import ccall unsafe "rl_on_new_line_with_prompt"
  rl_on_new_line_with_prompt :: IO CInt

{-# LINE 769 "System/Console/Readline.hsc" #-}

resetLineState :: IO ()
resetLineState = do rl_reset_line_state; return ()
foreign import ccall unsafe "rl_reset_line_state"
  rl_reset_line_state :: IO CInt

message :: String -> IO ()
message s = withCString s hs_rl_message
foreign import ccall unsafe "hs_rl_message"
  hs_rl_message :: Ptr CChar -> IO ()

clearMessage :: IO ()
clearMessage = do rl_clear_message; return ()
foreign import ccall unsafe "rl_clear_message"
  rl_clear_message :: IO CInt


{-# LINE 786 "System/Console/Readline.hsc" #-}
foreign import ccall unsafe "rl_save_prompt" savePrompt :: IO ()

foreign import ccall unsafe "rl_restore_prompt" restorePrompt :: IO ()

{-# LINE 790 "System/Console/Readline.hsc" #-}

------------------------------------------------------------------------
-- Modifying Text.

insertText :: String -> IO ()
insertText s = do withCString s rl_insert_text; return ()
foreign import ccall unsafe "rl_insert_text"
  rl_insert_text :: Ptr CChar -> IO CInt

deleteText :: Int -> Int -> IO ()
deleteText start end = do
    rl_delete_text (fromIntegral start) (fromIntegral end)
    return ()
foreign import ccall unsafe "rl_delete_text"
  rl_delete_text :: CInt -> CInt -> IO CInt

copyText :: Int -> Int -> IO String
copyText start end = do
    ptr <- rl_copy_text (fromIntegral start) (fromIntegral end)
    text <- peekCString ptr
    free ptr
    return text
foreign import ccall unsafe "rl_copy_text"
  rl_copy_text :: CInt -> CInt -> IO (Ptr CChar)

killText :: Int -> Int -> IO ()
killText start end = do
    rl_kill_text (fromIntegral start) (fromIntegral end)
    return ()
foreign import ccall unsafe "rl_kill_text"
  rl_kill_text :: CInt -> CInt -> IO CInt

------------------------------------------------------------------------
-- Utility functions.

readKey :: IO Char
readKey = liftM (chr . fromIntegral) rl_read_key
foreign import ccall unsafe "rl_read_key"
  rl_read_key :: IO CInt

stuffChar :: Char -> IO Bool
stuffChar key = liftM (/= 0) (rl_stuff_char (fromIntegral (ord key)))
foreign import ccall unsafe "rl_stuff_char"
  rl_stuff_char :: CInt -> IO CInt

initialize :: IO ()
initialize = do rl_initialize; return ()
foreign import ccall unsafe "rl_initialize"
  rl_initialize :: IO CInt

resetTerminal :: Maybe String -> IO ()
resetTerminal name = do
    maybeWith withCString name rl_reset_terminal
    return ()
foreign import ccall unsafe "rl_reset_terminal"
  rl_reset_terminal :: Ptr CChar -> IO CInt

ding :: IO Bool
ding = liftM (== 0) rl_ding

{-# LINE 850 "System/Console/Readline.hsc" #-}
foreign import ccall unsafe "rl_ding" rl_ding :: IO CInt

{-# LINE 854 "System/Console/Readline.hsc" #-}


{-# LINE 856 "System/Console/Readline.hsc" #-}
displayMatchList :: [String] -> IO ()
displayMatchList matches =
    withMany withCString matches $ \matchPtrs ->
        withArray0 nullPtr (nullPtr:matchPtrs) $ \matchesPtr ->
            rl_display_match_list
                matchesPtr
                (fromIntegral (length matches))
                (fromIntegral (maximum (map length matches)))
foreign import ccall unsafe "rl_display_match_list"
  rl_display_match_list :: Ptr (Ptr CChar) -> CInt -> CInt -> IO ()

{-# LINE 867 "System/Console/Readline.hsc" #-}

------------------------------------------------------------------------
-- Alternate Interface.

type Handler = Ptr CChar -> IO ()

callbackHandlerInstall :: String -> (String -> IO ()) -> IO (IO ())
callbackHandlerInstall prompt lhandler = do
    lhandlerPtr <- exportHandler $ \linePtr -> peekCString linePtr >>= lhandler
    withCString prompt $ \promptPtr -> do
        rl_callback_handler_install promptPtr lhandlerPtr
    return (do rl_callback_handler_remove; freeHaskellFunPtr lhandlerPtr)
foreign import ccall "wrapper"
  exportHandler :: Handler -> IO (FunPtr Handler)
foreign import ccall unsafe "rl_callback_handler_install"
  rl_callback_handler_install :: Ptr CChar -> FunPtr Handler -> IO ()
foreign import ccall unsafe "rl_callback_handler_remove"
  rl_callback_handler_remove :: IO ()

foreign import ccall "rl_callback_read_char" 
  callbackReadChar :: IO ()

------------------------------------------------------------------------
-- Readline Signal Handling.


{-# LINE 893 "System/Console/Readline.hsc" #-}
setCatchSignals :: Bool -> IO ()
setCatchSignals cat = poke rl_catch_signals (if cat then 1 else 0)

getCatchSignals :: IO Bool
getCatchSignals = liftM (/= 0) (peek rl_catch_signals)

foreign import ccall "&" rl_catch_signals :: Ptr CInt

setCatchSigwinch :: Bool -> IO ()
setCatchSigwinch cat = poke rl_catch_sigwinch (if cat then 1 else 0)

getCatchSigwinch :: IO Bool
getCatchSigwinch = liftM (/= 0) (peek rl_catch_sigwinch)

foreign import ccall "&" rl_catch_sigwinch :: Ptr CInt

foreign import ccall unsafe "rl_cleanup_after_signal" cleanupAfterSignal :: IO ()

foreign import ccall unsafe "rl_free_line_state" freeLineState :: IO ()

foreign import ccall unsafe "rl_reset_after_signal" resetAfterSignal :: IO ()

foreign import ccall unsafe "rl_resize_terminal" resizeTerminal :: IO ()

{-# LINE 917 "System/Console/Readline.hsc" #-}

setSignals :: IO ()
setSignals = do rl_set_signals; return ()
foreign import ccall unsafe "rl_set_signals"
  rl_set_signals :: IO CInt

clearSignals :: IO ()
clearSignals = do rl_clear_signals; return ()
foreign import ccall unsafe "rl_clear_signals"
  rl_clear_signals :: IO CInt

------------------------------------------------------------------------
-- Completion functions.

completeInternal :: Char -> IO ()
completeInternal what = do
    rl_complete_internal (fromIntegral (ord what))
    return ()
foreign import ccall "rl_complete_internal"
  rl_complete_internal :: CInt -> IO CInt

complete :: Int -> Char -> IO Int
complete n key =
    liftM fromIntegral $
        rl_complete (fromIntegral n) (fromIntegral (ord key))
foreign import ccall "rl_complete"
  rl_complete :: CInt -> CInt -> IO CInt

possibleCompletions :: Int -> Char -> IO Int
possibleCompletions n key =
    liftM fromIntegral $
        rl_possible_completions (fromIntegral n) (fromIntegral (ord key))
foreign import ccall "rl_possible_completions"
  rl_possible_completions :: CInt -> CInt -> IO CInt

insertCompletions :: Int -> Char -> IO Int
insertCompletions n key =
    liftM fromIntegral $
        rl_insert_completions (fromIntegral n) (fromIntegral (ord key))
foreign import ccall "rl_insert_completions"
  rl_insert_completions :: CInt -> CInt -> IO CInt

type Generator = Ptr CChar -> CInt -> IO (Ptr CChar)

singleToWhole :: Generator -> String -> IO [String]
singleToWhole f text =
    withCString text $ \textPtr -> let
        loop n = do
            ptr <- f textPtr n
            if ptr == nullPtr
                then return []
                else do
                    str <- peekCString ptr
                    free ptr
                    rest <- loop (n+1)
                    return (str:rest)
        in loop 0

wholeToSingle :: (String -> IO [String]) -> IO Generator
wholeToSingle f = do
    ref <- newIORef []
    return $ \textPtr state -> do
        when (state == 0) $ peekCString textPtr >>= f >>= writeIORef ref
        next <- readIORef ref
        case next of
            []   -> return nullPtr
            x:xs -> do
                writeIORef ref xs
                newCString x

completionMatches
    :: String -> (String -> IO [String]) -> IO (Maybe (String, [String]))
completionMatches text entry =
    withCString text $ \textPtr -> do
        entryPtr <- wholeToSingle entry >>= exportGenerator
        matchesPtr <- rl_completion_matches textPtr entryPtr
        freeHaskellFunPtr entryPtr
        if matchesPtr == nullPtr then return Nothing else do
            matchPtrs <- peekArray0 nullPtr matchesPtr
            (text':matches) <- mapM peekCString matchPtrs
            mapM_ free matchPtrs
            free matchesPtr
            return (Just (text', matches))

{-# LINE 1001 "System/Console/Readline.hsc" #-}
foreign import ccall "rl_completion_matches"
    rl_completion_matches :: Ptr CChar -> FunPtr Generator -> IO (Ptr (Ptr CChar))

{-# LINE 1007 "System/Console/Readline.hsc" #-}

filenameCompletionFunction :: String -> IO [String]
filenameCompletionFunction = singleToWhole rl_filename_completion_function

{-# LINE 1011 "System/Console/Readline.hsc" #-}
foreign import ccall unsafe "rl_filename_completion_function"
  rl_filename_completion_function :: Generator

{-# LINE 1017 "System/Console/Readline.hsc" #-}

usernameCompletionFunction :: String -> IO [String]
usernameCompletionFunction = singleToWhole rl_username_completion_function

{-# LINE 1021 "System/Console/Readline.hsc" #-}
foreign import ccall unsafe "rl_username_completion_function"
  rl_username_completion_function :: Generator

{-# LINE 1027 "System/Console/Readline.hsc" #-}

setCompletionEntryFunction :: Maybe (String -> IO [String]) -> IO ()
setCompletionEntryFunction fun =
    setFunPtr rl_completion_entry_function fun $ \f ->
        wholeToSingle f >>= exportGenerator
foreign import ccall "&" rl_completion_entry_function :: Ptr (FunPtr Generator)

foreign import ccall "wrapper"
    exportGenerator :: Generator -> IO (FunPtr Generator)

type Completer = Ptr CChar -> CInt -> CInt -> IO (Ptr (Ptr CChar))

setAttemptedCompletionFunction
    :: Maybe (String -> Int -> Int -> IO (Maybe (String, [String]))) -> IO ()
setAttemptedCompletionFunction fun =
    setFunPtr rl_attempted_completion_function fun $ \f ->
        exportCompleter $ \textPtr start end -> do
            text <- peekCString textPtr
            found <- f text (fromIntegral start) (fromIntegral end)
            case found of
                Nothing -> return nullPtr
                Just (text', matches) -> do
                    matchPtrs <- mapM newCString (text':matches)
                    matchesPtr <- mallocArray (length matchPtrs + 1)
                    pokeArray0 nullPtr matchesPtr matchPtrs
                    return matchesPtr

foreign import ccall "&"   rl_attempted_completion_function :: Ptr (FunPtr Completer)
foreign import ccall "wrapper"
    exportCompleter :: Completer -> IO (FunPtr Completer)


{-# LINE 1059 "System/Console/Readline.hsc" #-}
type StringFunc = IO (Ptr CChar)

foreign import ccall "&" rl_completion_word_break_hook 
    :: Ptr (FunPtr StringFunc)

foreign import ccall "wrapper" 
    exportStringFunc :: StringFunc -> IO (FunPtr StringFunc)

setCompletionWordBreakHook
    :: Maybe (IO (Maybe String)) -> IO ()
setCompletionWordBreakHook fun = 
    setFunPtr rl_completion_word_break_hook fun $ \f ->
        exportStringFunc $ do
            wordBreaks <- f
            case wordBreaks of
                Nothing -> return nullPtr
                Just wordBreaksString -> newCString wordBreaksString


{-# LINE 1078 "System/Console/Readline.hsc" #-}

type Quoter = Ptr CChar -> CInt -> Ptr CChar -> IO (Ptr CChar)

setFilenameQuotingFunction
    :: Maybe (String -> Bool -> Ptr CChar -> IO String) -> IO ()
setFilenameQuotingFunction fun =
    setFunPtr_freeIf
        (\oldPtr -> oldPtr /= nullFunPtr && oldPtr /= rl_quote_filename)
        rl_filename_quoting_function fun $ \f ->
        exportQuoter $ \textPtr typ qp -> do
            text <- peekCString textPtr
            s <- f text (typ == (2)) qp
{-# LINE 1090 "System/Console/Readline.hsc" #-}
            newCString s
foreign import ccall "&"  rl_filename_quoting_function :: Ptr (FunPtr Quoter)
foreign import ccall "wrapper"
  exportQuoter :: Quoter -> IO (FunPtr Quoter)

-- We must not freeHaskellFunPtr the original value of the
-- rl_filename_quoting_function variable, because it's a native C
-- function. But this value, rl_quote_filename, is a static function,
-- not exported by readline. So we read it from the variable at the
-- beginning and store it in a Haskell's global variable. We also
-- export its Haskell translation to be able to restore its behavior
-- by setFilenameQuotingFunction.

{-# NOINLINE rl_quote_filename #-}
rl_quote_filename :: FunPtr Quoter
rl_quote_filename = unsafePerformIO $ peek rl_filename_quoting_function

quoteFilename :: String -> Bool -> Ptr CChar -> IO String
quoteFilename text typ qp = do
    ptr <- withCString text $ \textPtr ->
        importQuoter rl_quote_filename
            textPtr
            (if typ then (1) else (2))
{-# LINE 1113 "System/Console/Readline.hsc" #-}
            qp
    s <- peekCString ptr
    free ptr
    return s
foreign import ccall "dynamic" importQuoter :: FunPtr Quoter -> Quoter

type Dequoter = Ptr CChar -> CInt -> IO (Ptr CChar)

setFilenameDequotingFunction :: Maybe (String -> Maybe Char -> IO String) -> IO ()
setFilenameDequotingFunction fun =
    setFunPtr rl_filename_dequoting_function fun $ \f ->
        exportDequoter $ \textPtr qc -> do
            text <- peekCString textPtr
            s <- f text (if qc==0 then Nothing else Just (chr (fromIntegral qc)))
            newCString s

foreign import ccall "&"rl_filename_dequoting_function :: Ptr (FunPtr Dequoter)

foreign import ccall "wrapper" 
  exportDequoter :: Dequoter -> IO (FunPtr Dequoter)

type IsQuoted = Ptr CChar -> CInt -> IO CInt

setCharIsQuotedP :: Maybe (String -> Int -> IO Bool) -> IO ()
setCharIsQuotedP fun =
    setFunPtr rl_char_is_quoted_p fun $ \f ->
        exportIsQuoted $ \textPtr index -> do
            text <- peekCString textPtr
            quoted <- f text (fromIntegral index)
            return (if quoted then 1 else 0)
foreign import ccall "&" rl_char_is_quoted_p :: Ptr (FunPtr IsQuoted)

foreign import ccall "wrapper"
  exportIsQuoted :: IsQuoted -> IO (FunPtr IsQuoted)

getCompletionQueryItems :: IO Int
getCompletionQueryItems =
    liftM fromIntegral (peek rl_completion_query_items)

setCompletionQueryItems :: Int -> IO ()
setCompletionQueryItems items =
    poke rl_completion_query_items (fromIntegral items)

foreign import ccall "&" rl_completion_query_items :: Ptr CInt

getBasicWordBreakCharacters :: IO String
getBasicWordBreakCharacters = getCharacters rl_basic_word_break_characters

setBasicWordBreakCharacters :: String -> IO ()
setBasicWordBreakCharacters =
    setCharacters_freeIf
        (/= orig_rl_basic_word_break_characters)
        rl_basic_word_break_characters

foreign import ccall "&" rl_basic_word_break_characters :: Ptr (Ptr CChar)

-- Similarly to rl_quote_filename, we must be able to detect the
-- original pointer to a static char array.

{-# NOINLINE orig_rl_basic_word_break_characters #-}
orig_rl_basic_word_break_characters :: Ptr CChar
orig_rl_basic_word_break_characters = unsafePerformIO $
    peek rl_basic_word_break_characters

getBasicQuoteCharacters :: IO String
getBasicQuoteCharacters = getCharacters rl_basic_quote_characters

setBasicQuoteCharacters :: String -> IO ()
setBasicQuoteCharacters =
    setCharacters_freeIf
        (/= orig_rl_basic_quote_characters)
        rl_basic_quote_characters

foreign import ccall "&" rl_basic_quote_characters :: Ptr (Ptr CChar)

{-# NOINLINE orig_rl_basic_quote_characters #-}
orig_rl_basic_quote_characters :: Ptr CChar
orig_rl_basic_quote_characters = unsafePerformIO $
    peek rl_basic_quote_characters

getCompleterWordBreakCharacters :: IO String
getCompleterWordBreakCharacters = getCharacters rl_completer_word_break_characters

setCompleterWordBreakCharacters :: String -> IO ()
setCompleterWordBreakCharacters =
    setCharacters_freeIf
        (\oldPtr -> oldPtr /= nullPtr &&
                    oldPtr /= orig_rl_basic_word_break_characters)
        rl_completer_word_break_characters

foreign import ccall "&" rl_completer_word_break_characters :: Ptr (Ptr CChar)

getCompleterQuoteCharacters :: IO String
getCompleterQuoteCharacters = getCharacters rl_completer_quote_characters

setCompleterQuoteCharacters :: String -> IO ()
setCompleterQuoteCharacters cs = do
    oldPtr <- peek rl_completer_quote_characters
    when (oldPtr /= nullPtr) $ free oldPtr
    -- I think that rl_completer_quote_characters should never be empty
    -- but can be NULL.
    newPtr <- if null cs
        then return nullPtr
        else do
            ptr <- mallocArray (length cs + 1)
            pokeArray0 0 ptr (map castCharToCChar cs)
            return ptr
    poke rl_completer_quote_characters newPtr

foreign import ccall "&" rl_completer_quote_characters :: Ptr (Ptr CChar)

getFilenameQuoteCharacters :: IO String
getFilenameQuoteCharacters = getCharacters rl_filename_quote_characters

setFilenameQuoteCharacters :: String -> IO ()
setFilenameQuoteCharacters = setCharacters rl_filename_quote_characters

foreign import ccall "&" rl_filename_quote_characters :: Ptr (Ptr CChar)

getSpecialPrefixes :: IO String
getSpecialPrefixes = getCharacters rl_special_prefixes

setSpecialPrefixes :: String -> IO ()
setSpecialPrefixes = setCharacters rl_special_prefixes

foreign import ccall "&" rl_special_prefixes :: Ptr (Ptr CChar)

getCompletionAppendCharacter :: IO (Maybe Char)
getCompletionAppendCharacter = do
    ch <- peek rl_completion_append_character
    return $ if ch == 0 then Nothing else Just (chr (fromIntegral ch))

setCompletionAppendCharacter :: Maybe Char -> IO ()
setCompletionAppendCharacter ch =
    poke rl_completion_append_character (maybe 0 (fromIntegral . ord) ch)

foreign import ccall "&" rl_completion_append_character :: Ptr CInt

setIgnoreCompletionDuplicates :: Bool -> IO ()
setIgnoreCompletionDuplicates ign =
    poke rl_ignore_completion_duplicates (if ign then 1 else 0)

getIgnoreCompletionDuplicates :: IO Bool
getIgnoreCompletionDuplicates =
    liftM (/= 0) (peek rl_ignore_completion_duplicates)

foreign import ccall "&" rl_ignore_completion_duplicates :: Ptr CInt

setFilenameCompletionDesired :: Bool -> IO ()
setFilenameCompletionDesired comp =
    poke rl_filename_completion_desired (if comp then 1 else 0)

getFilenameCompletionDesired :: IO Bool
getFilenameCompletionDesired =
    liftM (/= 0) (peek rl_filename_completion_desired)

foreign import ccall "&" rl_filename_completion_desired :: Ptr CInt

setFilenameQuotingDesired :: Bool -> IO ()
setFilenameQuotingDesired quot =
    poke rl_filename_quoting_desired (if quot then 1 else 0)

getFilenameQuotingDesired :: IO Bool
getFilenameQuotingDesired =
    liftM (/= 0) (peek rl_filename_quoting_desired)

foreign import ccall "&" rl_filename_quoting_desired :: Ptr CInt

setInhibitCompletion :: Bool -> IO ()
setInhibitCompletion inh = poke rl_inhibit_completion (if inh then 1 else 0)

getInhibitCompletion :: IO Bool
getInhibitCompletion = liftM (/= 0) (peek rl_inhibit_completion)

foreign import ccall "&" rl_attempted_completion_over :: Ptr CInt

getAttemptedCompletionOver :: IO Bool
getAttemptedCompletionOver = 
    liftM (/=0) (peek rl_attempted_completion_over)

setAttemptedCompletionOver :: Bool -> IO ()
setAttemptedCompletionOver over = 
    poke rl_attempted_completion_over (if over then 1 else 0)

foreign import ccall "&" rl_inhibit_completion :: Ptr CInt

type Ignorer = Ptr (Ptr CChar) -> IO CInt

setIgnoreSomeCompletionsFunction :: Maybe ([String] -> IO [String]) -> IO ()
-- The function may not make the list longer!
setIgnoreSomeCompletionsFunction fun =
    setFunPtr rl_ignore_some_completions_function fun $ \f ->
        exportIgnorer $ \matchesPtr -> do
            matchPtrs <- peekArray0 nullPtr matchesPtr
            matches <- mapM peekCString matchPtrs
            mapM_ free matchPtrs
            f matches >>= mapM newCString >>= pokeArray0 nullPtr matchesPtr
            return 0
foreign import ccall "&" rl_ignore_some_completions_function :: Ptr (FunPtr Ignorer)

foreign import ccall "wrapper"
  exportIgnorer :: Ignorer -> IO (FunPtr Ignorer)

type DirCompleter = Ptr (Ptr CChar) -> IO CInt

setDirectoryCompletionHook :: Maybe (String -> IO String) -> IO ()
setDirectoryCompletionHook fun =
    setFunPtr rl_directory_completion_hook fun $ \f ->
        exportDirCompleter $ \dirPtrPtr -> do
            oldDirPtr <- peek dirPtrPtr
            oldDir <- peekCString oldDirPtr
            free oldDirPtr
            newDirPtr <- f oldDir >>= newCString
            poke dirPtrPtr newDirPtr
            return 0
foreign import ccall "&" rl_directory_completion_hook :: Ptr (FunPtr DirCompleter)
foreign import ccall "wrapper"
    exportDirCompleter :: DirCompleter -> IO (FunPtr DirCompleter)


{-# LINE 1333 "System/Console/Readline.hsc" #-}
type Displayer = Ptr (Ptr CChar) -> CInt -> CInt -> IO ()

setCompletionDisplayMatchesHook :: Maybe ([String] -> IO ()) -> IO ()
setCompletionDisplayMatchesHook fun =
    setFunPtr rl_completion_display_matches_hook fun $ \f ->
        exportDisplayHook $ \matchesPtr _ _ ->
            peekArray0 nullPtr matchesPtr >>= mapM peekCString >>= f
foreign import ccall "&" rl_completion_display_matches_hook :: Ptr (FunPtr Displayer)
foreign import ccall "wrapper"
    exportDisplayHook :: Displayer -> IO (FunPtr Displayer)

{-# LINE 1344 "System/Console/Readline.hsc" #-}

setCharacters_freeIf :: (Ptr CChar -> Bool) -> Ptr (Ptr CChar) -> String -> IO ()
setCharacters_freeIf pred variable chars = do
    oldPtr <- peek variable
    when (pred oldPtr) $ free oldPtr
    newPtr <- mallocArray (length chars + 1)
    pokeArray0 0 newPtr (map castCharToCChar chars)
    poke variable newPtr

setCharacters :: Ptr (Ptr CChar) -> String -> IO ()
setCharacters = setCharacters_freeIf (/= nullPtr)

getCharacters :: Ptr (Ptr CChar) -> IO String
getCharacters variable = do
    ptr <- peek variable
    if ptr == nullPtr then return "" else do
        cs <- peekArray0 0 ptr
        return (map castCCharToChar cs)