{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
--  GIMP Toolkit (GTK) UTF aware string marshalling
--
--  Author : Axel Simon
--
--  Created: 22 June 2001
--
--  Copyright (c) 1999..2002 Axel Simon
--
--  This library is free software; you can redistribute it and/or
--  modify it under the terms of the GNU Lesser General Public
--  License as published by the Free Software Foundation; either
--  version 2.1 of the License, or (at your option) any later version.
--
--  This library is distributed in the hope that it will be useful,
--  but WITHOUT ANY WARRANTY; without even the implied warranty of
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
--  Lesser General Public License for more details.
--
-- |
-- Maintainer  : gtk2hs-users@lists.sourceforge.net
-- Stability   : provisional
-- Portability : portable (depends on GHC)
--
-- This module adds CString-like functions that handle UTF8 strings.
--

module System.Glib.UTFString (
  GlibString(..),
  readUTFString,
  readCString,
  withUTFStrings,
  withUTFStringArray,
  withUTFStringArray0,
  peekUTFStringArray,
  peekUTFStringArray0,
  readUTFStringArray0,
  UTFCorrection,
  ofsToUTF,
  ofsFromUTF,

  glibToString,
  stringToGlib,

  DefaultGlibString,

  GlibFilePath(..),
  withUTFFilePaths,
  withUTFFilePathArray,
  withUTFFilePathArray0,
  peekUTFFilePathArray0,
  readUTFFilePathArray0
  ) where

import Codec.Binary.UTF8.String
import Control.Applicative ((<$>))
import Control.Monad (liftM)
import Data.Char (ord, chr)
import Data.Maybe (maybe)
import Data.String (IsString)
import Data.Monoid (Monoid)
import System.Glib.FFI
import qualified Data.Text as T (replace, length, pack, unpack, Text)
import qualified Data.Text.Foreign as T
       (withCStringLen, peekCStringLen)
import Data.ByteString (useAsCString)
import Data.Text.Encoding (encodeUtf8)

class (IsString s, Monoid s, Show s) => GlibString s where
    -- | Like 'withCString' but using the UTF-8 encoding.
    --
    withUTFString :: s -> (CString -> IO a) -> IO a

    -- | Like 'withCStringLen' but using the UTF-8 encoding.
    --
    withUTFStringLen :: s -> (CStringLen -> IO a) -> IO a

    -- | Like 'peekCString' but using the UTF-8 encoding.
    --
    peekUTFString :: CString -> IO s

    -- | Like 'maybePeek' 'peekCString' but using the UTF-8 encoding to retrieve
    -- UTF-8 from a 'CString' which may be the 'nullPtr'.
    --
    maybePeekUTFString :: CString -> IO (Maybe s)

    -- | Like 'peekCStringLen' but using the UTF-8 encoding.
    --
    peekUTFStringLen :: CStringLen -> IO s

    -- | Like 'newCString' but using the UTF-8 encoding.
    --
    newUTFString :: s -> IO CString

    -- | Like  Define newUTFStringLen to emit UTF-8.
    --
    newUTFStringLen :: s -> IO CStringLen

    -- | Create a list of offset corrections.
    --
    genUTFOfs :: s -> UTFCorrection

    -- | Length of the string in characters
    --
    stringLength :: s -> Int

    -- Escape percent signs (used in MessageDialog)
    unPrintf :: s -> s

-- GTK+ has a lot of asserts that the ptr is not NULL even if the length is 0
-- Until they fix this we need to fudge pointer values to keep the noise level
-- in the logs.
noNullPtrs :: CStringLen -> CStringLen
noNullPtrs :: CStringLen -> CStringLen
noNullPtrs (Ptr CChar
p, Int
0) | Ptr CChar
p Ptr CChar -> Ptr CChar -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr CChar
forall a. Ptr a
nullPtr = (Ptr CChar -> Int -> Ptr CChar
forall a b. Ptr a -> Int -> Ptr b
plusPtr Ptr CChar
p Int
1, Int
0)
noNullPtrs CStringLen
s = CStringLen
s

instance GlibString [Char] where
    withUTFString :: [Char] -> (Ptr CChar -> IO a) -> IO a
withUTFString = [Char] -> (Ptr CChar -> IO a) -> IO a
forall a. [Char] -> (Ptr CChar -> IO a) -> IO a
withCAString ([Char] -> (Ptr CChar -> IO a) -> IO a)
-> ([Char] -> [Char]) -> [Char] -> (Ptr CChar -> IO a) -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char]
encodeString
    withUTFStringLen :: [Char] -> (CStringLen -> IO a) -> IO a
withUTFStringLen [Char]
s CStringLen -> IO a
f = [Char] -> (CStringLen -> IO a) -> IO a
forall a. [Char] -> (CStringLen -> IO a) -> IO a
withCAStringLen ([Char] -> [Char]
encodeString [Char]
s) (CStringLen -> IO a
f (CStringLen -> IO a)
-> (CStringLen -> CStringLen) -> CStringLen -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CStringLen -> CStringLen
noNullPtrs)
    peekUTFString :: Ptr CChar -> IO [Char]
peekUTFString = ([Char] -> [Char]) -> IO [Char] -> IO [Char]
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM [Char] -> [Char]
decodeString (IO [Char] -> IO [Char])
-> (Ptr CChar -> IO [Char]) -> Ptr CChar -> IO [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr CChar -> IO [Char]
peekCAString
    maybePeekUTFString :: Ptr CChar -> IO (Maybe [Char])
maybePeekUTFString = (Maybe [Char] -> Maybe [Char])
-> IO (Maybe [Char]) -> IO (Maybe [Char])
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (Maybe [Char]
-> ([Char] -> Maybe [Char]) -> Maybe [Char] -> Maybe [Char]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Maybe [Char]
forall a. Maybe a
Nothing ([Char] -> Maybe [Char]
forall a. a -> Maybe a
Just ([Char] -> Maybe [Char])
-> ([Char] -> [Char]) -> [Char] -> Maybe [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char]
decodeString)) (IO (Maybe [Char]) -> IO (Maybe [Char]))
-> (Ptr CChar -> IO (Maybe [Char]))
-> Ptr CChar
-> IO (Maybe [Char])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Ptr CChar -> IO [Char]) -> Ptr CChar -> IO (Maybe [Char])
forall a b. (Ptr a -> IO b) -> Ptr a -> IO (Maybe b)
maybePeek Ptr CChar -> IO [Char]
peekCAString
    peekUTFStringLen :: CStringLen -> IO [Char]
peekUTFStringLen = ([Char] -> [Char]) -> IO [Char] -> IO [Char]
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM [Char] -> [Char]
decodeString (IO [Char] -> IO [Char])
-> (CStringLen -> IO [Char]) -> CStringLen -> IO [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CStringLen -> IO [Char]
peekCAStringLen
    newUTFString :: [Char] -> IO (Ptr CChar)
newUTFString = [Char] -> IO (Ptr CChar)
newCAString ([Char] -> IO (Ptr CChar))
-> ([Char] -> [Char]) -> [Char] -> IO (Ptr CChar)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char]
encodeString
    newUTFStringLen :: [Char] -> IO CStringLen
newUTFStringLen = [Char] -> IO CStringLen
newCAStringLen ([Char] -> IO CStringLen)
-> ([Char] -> [Char]) -> [Char] -> IO CStringLen
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char]
encodeString
    genUTFOfs :: [Char] -> UTFCorrection
genUTFOfs [Char]
str = [Int] -> UTFCorrection
UTFCorrection (Int -> [Char] -> [Int]
forall a. Num a => a -> [Char] -> [a]
gUO Int
0 [Char]
str)
      where
      gUO :: a -> [Char] -> [a]
gUO a
n [] = []
      gUO a
n (Char
x:[Char]
xs) | Char -> Int
ord Char
xInt -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<=Int
0x007F = a -> [Char] -> [a]
gUO (a
na -> a -> a
forall a. Num a => a -> a -> a
+a
1) [Char]
xs
                   | Char -> Int
ord Char
xInt -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<=Int
0x07FF = a
na -> [a] -> [a]
forall a. a -> [a] -> [a]
:a -> [Char] -> [a]
gUO (a
na -> a -> a
forall a. Num a => a -> a -> a
+a
1) [Char]
xs
                   | Char -> Int
ord Char
xInt -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<=Int
0xFFFF = a
na -> [a] -> [a]
forall a. a -> [a] -> [a]
:a
na -> [a] -> [a]
forall a. a -> [a] -> [a]
:a -> [Char] -> [a]
gUO (a
na -> a -> a
forall a. Num a => a -> a -> a
+a
1) [Char]
xs
                   | Bool
otherwise     = a
na -> [a] -> [a]
forall a. a -> [a] -> [a]
:a
na -> [a] -> [a]
forall a. a -> [a] -> [a]
:a
na -> [a] -> [a]
forall a. a -> [a] -> [a]
:a -> [Char] -> [a]
gUO (a
na -> a -> a
forall a. Num a => a -> a -> a
+a
1) [Char]
xs
    stringLength :: [Char] -> Int
stringLength = [Char] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length
    unPrintf :: [Char] -> [Char]
unPrintf [Char]
s = [Char]
s [Char] -> (Char -> [Char]) -> [Char]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Char -> [Char]
forall (m :: * -> *).
(IsString (m Char), Monad m) =>
Char -> m Char
replace
        where
            replace :: Char -> m Char
replace Char
'%' = m Char
"%%"
            replace Char
c = Char -> m Char
forall (m :: * -> *) a. Monad m => a -> m a
return Char
c

foreign import ccall unsafe "string.h strlen" c_strlen
    :: CString -> IO CSize

instance GlibString T.Text where
    withUTFString :: Text -> (Ptr CChar -> IO a) -> IO a
withUTFString = ByteString -> (Ptr CChar -> IO a) -> IO a
forall a. ByteString -> (Ptr CChar -> IO a) -> IO a
useAsCString (ByteString -> (Ptr CChar -> IO a) -> IO a)
-> (Text -> ByteString) -> Text -> (Ptr CChar -> IO a) -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
encodeUtf8
    withUTFStringLen :: Text -> (CStringLen -> IO a) -> IO a
withUTFStringLen Text
s CStringLen -> IO a
f = Text -> (CStringLen -> IO a) -> IO a
forall a. Text -> (CStringLen -> IO a) -> IO a
T.withCStringLen Text
s (CStringLen -> IO a
f (CStringLen -> IO a)
-> (CStringLen -> CStringLen) -> CStringLen -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CStringLen -> CStringLen
noNullPtrs)
    peekUTFString :: Ptr CChar -> IO Text
peekUTFString Ptr CChar
s = do
        CSize
len <- Ptr CChar -> IO CSize
c_strlen Ptr CChar
s
        CStringLen -> IO Text
T.peekCStringLen (Ptr CChar
s, CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
len)
    maybePeekUTFString :: Ptr CChar -> IO (Maybe Text)
maybePeekUTFString = (Ptr CChar -> IO Text) -> Ptr CChar -> IO (Maybe Text)
forall a b. (Ptr a -> IO b) -> Ptr a -> IO (Maybe b)
maybePeek Ptr CChar -> IO Text
forall s. GlibString s => Ptr CChar -> IO s
peekUTFString
    peekUTFStringLen :: CStringLen -> IO Text
peekUTFStringLen = CStringLen -> IO Text
T.peekCStringLen
    newUTFString :: Text -> IO (Ptr CChar)
newUTFString = [Char] -> IO (Ptr CChar)
forall s. GlibString s => s -> IO (Ptr CChar)
newUTFString ([Char] -> IO (Ptr CChar))
-> (Text -> [Char]) -> Text -> IO (Ptr CChar)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Char]
T.unpack -- TODO optimize
    newUTFStringLen :: Text -> IO CStringLen
newUTFStringLen = [Char] -> IO CStringLen
forall s. GlibString s => s -> IO CStringLen
newUTFStringLen ([Char] -> IO CStringLen)
-> (Text -> [Char]) -> Text -> IO CStringLen
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Char]
T.unpack -- TODO optimize
    genUTFOfs :: Text -> UTFCorrection
genUTFOfs = [Char] -> UTFCorrection
forall s. GlibString s => s -> UTFCorrection
genUTFOfs ([Char] -> UTFCorrection)
-> (Text -> [Char]) -> Text -> UTFCorrection
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Char]
T.unpack -- TODO optimize
    stringLength :: Text -> Int
stringLength = Text -> Int
T.length
    unPrintf :: Text -> Text
unPrintf = Text -> Text -> Text -> Text
T.replace Text
"%" Text
"%%"

glibToString :: T.Text -> String
glibToString :: Text -> [Char]
glibToString = Text -> [Char]
T.unpack

stringToGlib :: String -> T.Text
stringToGlib :: [Char] -> Text
stringToGlib = [Char] -> Text
T.pack

-- | Like like 'peekUTFString' but then frees the string using g_free
--
readUTFString :: GlibString s => CString -> IO s
readUTFString :: Ptr CChar -> IO s
readUTFString Ptr CChar
strPtr = do
  s
str <- Ptr CChar -> IO s
forall s. GlibString s => Ptr CChar -> IO s
peekUTFString Ptr CChar
strPtr
  Ptr CChar -> IO ()
forall a. Ptr a -> IO ()
g_free Ptr CChar
strPtr
  s -> IO s
forall (m :: * -> *) a. Monad m => a -> m a
return s
str

-- | Like 'peekCString' but then frees the string using @g_free@.
--
readCString :: CString -> IO String
readCString :: Ptr CChar -> IO [Char]
readCString Ptr CChar
strPtr = do
  [Char]
str <- Ptr CChar -> IO [Char]
peekCAString Ptr CChar
strPtr
  Ptr CChar -> IO ()
forall a. Ptr a -> IO ()
g_free Ptr CChar
strPtr
  [Char] -> IO [Char]
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
str

foreign import ccall unsafe "g_free"
  g_free :: Ptr a -> IO ()

-- | Temporarily allocate a list of UTF-8 'CString's.
--
withUTFStrings :: GlibString s => [s] -> ([CString] -> IO a) -> IO a
withUTFStrings :: [s] -> ([Ptr CChar] -> IO a) -> IO a
withUTFStrings [s]
hsStrs = [s] -> [Ptr CChar] -> ([Ptr CChar] -> IO a) -> IO a
forall s a.
GlibString s =>
[s] -> [Ptr CChar] -> ([Ptr CChar] -> IO a) -> IO a
withUTFStrings' [s]
hsStrs []
  where withUTFStrings' :: GlibString s => [s] -> [CString] -> ([CString] -> IO a) -> IO a
        withUTFStrings' :: [s] -> [Ptr CChar] -> ([Ptr CChar] -> IO a) -> IO a
withUTFStrings' []     [Ptr CChar]
cs [Ptr CChar] -> IO a
body = [Ptr CChar] -> IO a
body ([Ptr CChar] -> [Ptr CChar]
forall a. [a] -> [a]
reverse [Ptr CChar]
cs)
        withUTFStrings' (s
s:[s]
ss) [Ptr CChar]
cs [Ptr CChar] -> IO a
body = s -> (Ptr CChar -> IO a) -> IO a
forall s a. GlibString s => s -> (Ptr CChar -> IO a) -> IO a
withUTFString s
s ((Ptr CChar -> IO a) -> IO a) -> (Ptr CChar -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
c ->
                                         [s] -> [Ptr CChar] -> ([Ptr CChar] -> IO a) -> IO a
forall s a.
GlibString s =>
[s] -> [Ptr CChar] -> ([Ptr CChar] -> IO a) -> IO a
withUTFStrings' [s]
ss (Ptr CChar
cPtr CChar -> [Ptr CChar] -> [Ptr CChar]
forall a. a -> [a] -> [a]
:[Ptr CChar]
cs) [Ptr CChar] -> IO a
body

-- | Temporarily allocate an array of UTF-8 encoded 'CString's.
--
withUTFStringArray :: GlibString s => [s] -> (Ptr CString -> IO a) -> IO a
withUTFStringArray :: [s] -> (Ptr (Ptr CChar) -> IO a) -> IO a
withUTFStringArray [s]
hsStr Ptr (Ptr CChar) -> IO a
body =
  [s] -> ([Ptr CChar] -> IO a) -> IO a
forall s a. GlibString s => [s] -> ([Ptr CChar] -> IO a) -> IO a
withUTFStrings [s]
hsStr (([Ptr CChar] -> IO a) -> IO a) -> ([Ptr CChar] -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \[Ptr CChar]
cStrs -> do
  [Ptr CChar] -> (Ptr (Ptr CChar) -> IO a) -> IO a
forall a b. Storable a => [a] -> (Ptr a -> IO b) -> IO b
withArray [Ptr CChar]
cStrs Ptr (Ptr CChar) -> IO a
body

-- | Temporarily allocate a null-terminated array of UTF-8 encoded 'CString's.
--
withUTFStringArray0 :: GlibString s => [s] -> (Ptr CString -> IO a) -> IO a
withUTFStringArray0 :: [s] -> (Ptr (Ptr CChar) -> IO a) -> IO a
withUTFStringArray0 [s]
hsStr Ptr (Ptr CChar) -> IO a
body =
  [s] -> ([Ptr CChar] -> IO a) -> IO a
forall s a. GlibString s => [s] -> ([Ptr CChar] -> IO a) -> IO a
withUTFStrings [s]
hsStr (([Ptr CChar] -> IO a) -> IO a) -> ([Ptr CChar] -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \[Ptr CChar]
cStrs -> do
  Ptr CChar -> [Ptr CChar] -> (Ptr (Ptr CChar) -> IO a) -> IO a
forall a b. Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b
withArray0 Ptr CChar
forall a. Ptr a
nullPtr [Ptr CChar]
cStrs Ptr (Ptr CChar) -> IO a
body

-- | Convert an array (of the given length) of UTF-8 encoded 'CString's to a
--   list of Haskell 'String's.
--
peekUTFStringArray :: GlibString s => Int -> Ptr CString -> IO [s]
peekUTFStringArray :: Int -> Ptr (Ptr CChar) -> IO [s]
peekUTFStringArray Int
len Ptr (Ptr CChar)
cStrArr = do
  [Ptr CChar]
cStrs <- Int -> Ptr (Ptr CChar) -> IO [Ptr CChar]
forall a. Storable a => Int -> Ptr a -> IO [a]
peekArray Int
len Ptr (Ptr CChar)
cStrArr
  (Ptr CChar -> IO s) -> [Ptr CChar] -> IO [s]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Ptr CChar -> IO s
forall s. GlibString s => Ptr CChar -> IO s
peekUTFString [Ptr CChar]
cStrs

-- | Convert a null-terminated array of UTF-8 encoded 'CString's to a list of
--   Haskell 'String's.
--
peekUTFStringArray0 :: GlibString s => Ptr CString -> IO [s]
peekUTFStringArray0 :: Ptr (Ptr CChar) -> IO [s]
peekUTFStringArray0 Ptr (Ptr CChar)
cStrArr = do
  [Ptr CChar]
cStrs <- Ptr CChar -> Ptr (Ptr CChar) -> IO [Ptr CChar]
forall a. (Storable a, Eq a) => a -> Ptr a -> IO [a]
peekArray0 Ptr CChar
forall a. Ptr a
nullPtr Ptr (Ptr CChar)
cStrArr
  (Ptr CChar -> IO s) -> [Ptr CChar] -> IO [s]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Ptr CChar -> IO s
forall s. GlibString s => Ptr CChar -> IO s
peekUTFString [Ptr CChar]
cStrs

-- | Like 'peekUTFStringArray0' but then free the string array including all
-- strings.
--
-- To be used when functions indicate that their return value should be freed
-- with @g_strfreev@.
--
readUTFStringArray0 :: GlibString s => Ptr CString -> IO [s]
readUTFStringArray0 :: Ptr (Ptr CChar) -> IO [s]
readUTFStringArray0 Ptr (Ptr CChar)
cStrArr | Ptr (Ptr CChar)
cStrArr Ptr (Ptr CChar) -> Ptr (Ptr CChar) -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr (Ptr CChar)
forall a. Ptr a
nullPtr = [s] -> IO [s]
forall (m :: * -> *) a. Monad m => a -> m a
return []
                            | Bool
otherwise = do
  [Ptr CChar]
cStrs <- Ptr CChar -> Ptr (Ptr CChar) -> IO [Ptr CChar]
forall a. (Storable a, Eq a) => a -> Ptr a -> IO [a]
peekArray0 Ptr CChar
forall a. Ptr a
nullPtr Ptr (Ptr CChar)
cStrArr
  [s]
strings <- (Ptr CChar -> IO s) -> [Ptr CChar] -> IO [s]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Ptr CChar -> IO s
forall s. GlibString s => Ptr CChar -> IO s
peekUTFString [Ptr CChar]
cStrs
  Ptr (Ptr CChar) -> IO ()
forall a. Ptr a -> IO ()
g_strfreev Ptr (Ptr CChar)
cStrArr
  [s] -> IO [s]
forall (m :: * -> *) a. Monad m => a -> m a
return [s]
strings

foreign import ccall unsafe "g_strfreev"
  g_strfreev :: Ptr a -> IO ()

-- | Offset correction for String to UTF8 mapping.
--
newtype UTFCorrection = UTFCorrection [Int] deriving Int -> UTFCorrection -> [Char] -> [Char]
[UTFCorrection] -> [Char] -> [Char]
UTFCorrection -> [Char]
(Int -> UTFCorrection -> [Char] -> [Char])
-> (UTFCorrection -> [Char])
-> ([UTFCorrection] -> [Char] -> [Char])
-> Show UTFCorrection
forall a.
(Int -> a -> [Char] -> [Char])
-> (a -> [Char]) -> ([a] -> [Char] -> [Char]) -> Show a
showList :: [UTFCorrection] -> [Char] -> [Char]
$cshowList :: [UTFCorrection] -> [Char] -> [Char]
show :: UTFCorrection -> [Char]
$cshow :: UTFCorrection -> [Char]
showsPrec :: Int -> UTFCorrection -> [Char] -> [Char]
$cshowsPrec :: Int -> UTFCorrection -> [Char] -> [Char]
Show

ofsToUTF :: Int -> UTFCorrection -> Int
ofsToUTF :: Int -> UTFCorrection -> Int
ofsToUTF Int
n (UTFCorrection [Int]
oc) = [Int] -> Int
oTU [Int]
oc
  where
  oTU :: [Int] -> Int
oTU [] = Int
n
  oTU (Int
x:[Int]
xs) | Int
nInt -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<=Int
x = Int
n
             | Bool
otherwise = Int
1Int -> Int -> Int
forall a. Num a => a -> a -> a
+[Int] -> Int
oTU [Int]
xs

ofsFromUTF :: Int -> UTFCorrection -> Int
ofsFromUTF :: Int -> UTFCorrection -> Int
ofsFromUTF Int
n (UTFCorrection [Int]
oc) = Int -> [Int] -> Int
forall t. (Ord t, Num t) => t -> [t] -> t
oFU Int
n [Int]
oc
  where
  oFU :: t -> [t] -> t
oFU t
n [] = t
n
  oFU t
n (t
x:[t]
xs) | t
nt -> t -> Bool
forall a. Ord a => a -> a -> Bool
<=t
x = t
n
               | Bool
otherwise = t -> [t] -> t
oFU (t
nt -> t -> t
forall a. Num a => a -> a -> a
-t
1) [t]
xs

type DefaultGlibString = T.Text

class fp ~ FilePath => GlibFilePath fp where
    withUTFFilePath :: fp -> (CString -> IO a) -> IO a
    peekUTFFilePath :: CString -> IO fp

instance GlibFilePath FilePath where
    withUTFFilePath :: [Char] -> (Ptr CChar -> IO a) -> IO a
withUTFFilePath = Text -> (Ptr CChar -> IO a) -> IO a
forall s a. GlibString s => s -> (Ptr CChar -> IO a) -> IO a
withUTFString (Text -> (Ptr CChar -> IO a) -> IO a)
-> ([Char] -> Text) -> [Char] -> (Ptr CChar -> IO a) -> IO a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Text
T.pack
    peekUTFFilePath :: Ptr CChar -> IO [Char]
peekUTFFilePath Ptr CChar
f = Text -> [Char]
T.unpack (Text -> [Char]) -> IO Text -> IO [Char]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Ptr CChar -> IO Text
forall s. GlibString s => Ptr CChar -> IO s
peekUTFString Ptr CChar
f

withUTFFilePaths :: GlibFilePath fp => [fp] -> ([CString] -> IO a) -> IO a
withUTFFilePaths :: [fp] -> ([Ptr CChar] -> IO a) -> IO a
withUTFFilePaths [fp]
hsStrs = [fp] -> [Ptr CChar] -> ([Ptr CChar] -> IO a) -> IO a
forall fp a.
GlibFilePath fp =>
[fp] -> [Ptr CChar] -> ([Ptr CChar] -> IO a) -> IO a
withUTFFilePath' [fp]
hsStrs []
  where withUTFFilePath' :: GlibFilePath fp => [fp] -> [CString] -> ([CString] -> IO a) -> IO a
        withUTFFilePath' :: [fp] -> [Ptr CChar] -> ([Ptr CChar] -> IO a) -> IO a
withUTFFilePath' []       [Ptr CChar]
cs [Ptr CChar] -> IO a
body = [Ptr CChar] -> IO a
body ([Ptr CChar] -> [Ptr CChar]
forall a. [a] -> [a]
reverse [Ptr CChar]
cs)
        withUTFFilePath' (fp
fp:[fp]
fps) [Ptr CChar]
cs [Ptr CChar] -> IO a
body = fp -> (Ptr CChar -> IO a) -> IO a
forall fp a. GlibFilePath fp => fp -> (Ptr CChar -> IO a) -> IO a
withUTFFilePath fp
fp ((Ptr CChar -> IO a) -> IO a) -> (Ptr CChar -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \Ptr CChar
c ->
                                            [fp] -> [Ptr CChar] -> ([Ptr CChar] -> IO a) -> IO a
forall fp a.
GlibFilePath fp =>
[fp] -> [Ptr CChar] -> ([Ptr CChar] -> IO a) -> IO a
withUTFFilePath' [fp]
fps (Ptr CChar
cPtr CChar -> [Ptr CChar] -> [Ptr CChar]
forall a. a -> [a] -> [a]
:[Ptr CChar]
cs) [Ptr CChar] -> IO a
body

withUTFFilePathArray :: GlibFilePath fp => [fp] -> (Ptr CString -> IO a) -> IO a
withUTFFilePathArray :: [fp] -> (Ptr (Ptr CChar) -> IO a) -> IO a
withUTFFilePathArray [fp]
hsFP Ptr (Ptr CChar) -> IO a
body =
  [fp] -> ([Ptr CChar] -> IO a) -> IO a
forall fp a.
GlibFilePath fp =>
[fp] -> ([Ptr CChar] -> IO a) -> IO a
withUTFFilePaths [fp]
hsFP (([Ptr CChar] -> IO a) -> IO a) -> ([Ptr CChar] -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \[Ptr CChar]
cStrs -> do
  [Ptr CChar] -> (Ptr (Ptr CChar) -> IO a) -> IO a
forall a b. Storable a => [a] -> (Ptr a -> IO b) -> IO b
withArray [Ptr CChar]
cStrs Ptr (Ptr CChar) -> IO a
body

withUTFFilePathArray0 :: GlibFilePath fp => [fp] -> (Ptr CString -> IO a) -> IO a
withUTFFilePathArray0 :: [fp] -> (Ptr (Ptr CChar) -> IO a) -> IO a
withUTFFilePathArray0 [fp]
hsFP Ptr (Ptr CChar) -> IO a
body =
  [fp] -> ([Ptr CChar] -> IO a) -> IO a
forall fp a.
GlibFilePath fp =>
[fp] -> ([Ptr CChar] -> IO a) -> IO a
withUTFFilePaths [fp]
hsFP (([Ptr CChar] -> IO a) -> IO a) -> ([Ptr CChar] -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \[Ptr CChar]
cStrs -> do
  Ptr CChar -> [Ptr CChar] -> (Ptr (Ptr CChar) -> IO a) -> IO a
forall a b. Storable a => a -> [a] -> (Ptr a -> IO b) -> IO b
withArray0 Ptr CChar
forall a. Ptr a
nullPtr [Ptr CChar]
cStrs Ptr (Ptr CChar) -> IO a
body

peekUTFFilePathArray0 :: GlibFilePath fp => Ptr CString -> IO [fp]
peekUTFFilePathArray0 :: Ptr (Ptr CChar) -> IO [fp]
peekUTFFilePathArray0 Ptr (Ptr CChar)
cStrArr = do
  [Ptr CChar]
cStrs <- Ptr CChar -> Ptr (Ptr CChar) -> IO [Ptr CChar]
forall a. (Storable a, Eq a) => a -> Ptr a -> IO [a]
peekArray0 Ptr CChar
forall a. Ptr a
nullPtr Ptr (Ptr CChar)
cStrArr
  (Ptr CChar -> IO fp) -> [Ptr CChar] -> IO [fp]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Ptr CChar -> IO fp
forall fp. GlibFilePath fp => Ptr CChar -> IO fp
peekUTFFilePath [Ptr CChar]
cStrs

readUTFFilePathArray0 :: GlibFilePath fp => Ptr CString -> IO [fp]
readUTFFilePathArray0 :: Ptr (Ptr CChar) -> IO [fp]
readUTFFilePathArray0 Ptr (Ptr CChar)
cStrArr | Ptr (Ptr CChar)
cStrArr Ptr (Ptr CChar) -> Ptr (Ptr CChar) -> Bool
forall a. Eq a => a -> a -> Bool
== Ptr (Ptr CChar)
forall a. Ptr a
nullPtr = [fp] -> IO [fp]
forall (m :: * -> *) a. Monad m => a -> m a
return []
                              | Bool
otherwise = do
  [Ptr CChar]
cStrs <- Ptr CChar -> Ptr (Ptr CChar) -> IO [Ptr CChar]
forall a. (Storable a, Eq a) => a -> Ptr a -> IO [a]
peekArray0 Ptr CChar
forall a. Ptr a
nullPtr Ptr (Ptr CChar)
cStrArr
  [fp]
fps <- (Ptr CChar -> IO fp) -> [Ptr CChar] -> IO [fp]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Ptr CChar -> IO fp
forall fp. GlibFilePath fp => Ptr CChar -> IO fp
peekUTFFilePath [Ptr CChar]
cStrs
  Ptr (Ptr CChar) -> IO ()
forall a. Ptr a -> IO ()
g_strfreev Ptr (Ptr CChar)
cStrArr
  [fp] -> IO [fp]
forall (m :: * -> *) a. Monad m => a -> m a
return [fp]
fps