cedict-0.2.1: Data/Char/CEDICT/C/Walker.hs
{- }
An interface to the C stuff, as functions that walk up and down the arrays.
{ -}
module Data.Char.CEDICT.C.Walker where
import Data.Char.CEDICT.C.Data
import Data.Char.CEDICT.C.PtrWalker
import Data.Char.CEDICT.C.Declarations
import qualified Data.ByteString.UTF8
import qualified Data.ByteString
import Data.Ord
import Data.List
import System.IO.Unsafe
import Control.Arrow
import Control.Monad
import Foreign
import Foreign.C
import Foreign.Storable
import Foreign.Marshal.Array
searchST = binary st_elements st_length
searchTS = binary ts_elements ts_length
searchPD = trieReference d_trie [d_pins, d_defs]
searchPins = fmap (second head) . searchPD
searchDefs = fmap (second last) . searchPD
binary :: Ptr CString -> Ptr CInt -> Char -> String
binary listPtrs lenPtr char = search' listPtrs len
where
search' _ 0 = [char]
search' ptrs len =
case compare char leading of
LT -> search' ptrs $ halfLen
GT -> search' ptr $ halfLen + (len `mod` 2)
EQ -> tail str
where
leading = head str
halfLen = len `div` 2
ptr = plusPtr ptrs $ halfLen * advance
str = toUTF8String . pikachu $ ptr
len = fromIntegral . pikachu $ lenPtr
advance = sizeOf listPtrs
trieReference ::
Ptr CInt -> [Ptr CString] -> String -> Maybe ((String, String), [[String]])
trieReference _ [] _ = Nothing
trieReference triePtr dictPtrs s =
case trieSearch triePtr s of
Nothing -> Nothing
Just (strings, i) ->
if head ptrs == nullPtr then
Nothing
else
Just (strings, map form ptrs)
where
ptrs :: [CString]
ptrs = map peruse dictPtrs
where
peruse ptr = pikachu $ plusPtr ptr $ i * sizeOf ptr
form = splitter "" . toUTF8String
splitter s' string =
case string of
' ':'/':'/':' ':s -> reverse s' : splitter [] s
k:s -> splitter (k:s') s
[] -> [reverse s']
trieSearch :: Ptr CInt -> String -> Maybe ((String, String), Int)
trieSearch triePtr string = walkPtr triePtr $ walker "" string
walker _ [] = return Nothing
walker s' (k:s) = do
len <- liftM fromIntegral value
skipF'
rel <- liftM (binary len (fromEnum k)) pointer
case rel of
Just n -> do
skipF n -- Now we're at the character.
case s of
[] -> finish
_ -> do
skipF len -- Now we're at the character's jump entry.
jump <- liftM fromIntegral value
skipB len -- Back to the character.
case jump of
0 -> finish -- nowhere to go from here
_ -> do
skipB'
skipB n -- Time to go all the way back for...
skipF jump -- ...our big jump to the next list!
walker (k:s') s
Nothing -> return Nothing
where
finish = do
o <- offset
return $ Just ((reverse (k:s'), s), o)
binary arrayLen k ptr = walkPtr ptr $ jiggle k arrayLen
jiggle k 0 = return Nothing
jiggle k len = do
skipF halfLen
v <- value
case compare k (fromIntegral v) of
LT -> skipB halfLen >> jiggle k halfLen
GT -> jiggle k $ halfLen + (len `mod` 2)
EQ -> return Just `ap` offset
where
halfLen = len `div` 2
toUTF8String :: CString -> String
toUTF8String =
Data.ByteString.UTF8.toString . unsafePerformIO . Data.ByteString.packCString