{-# LANGUAGE CPP #-}
module Utils where
import Codec.Binary.UTF8.String (encodeString)
import Data.List (intercalate)
import Data.Maybe (fromMaybe)
-- for daemonTrace
import System.IO.Unsafe (unsafePerformIO)
import System.Log.Logger
-- | Safe 'head'.
maybeHead :: [a] -> Maybe a
maybeHead [] = Nothing
maybeHead (x:_) = Just x
-- | Safe substitute for (!!).
maybeNth :: Int -> [a] -> Maybe a
maybeNth _ [] = Nothing
maybeNth 0 xs = maybeHead xs
maybeNth n (_:xs) = maybeNth (n-1) xs
-- | Safe 'last'.
maybeLast :: [a] -> Maybe a
maybeLast [] = Nothing
maybeLast xs = Just $ last xs
-- | Extract the first component of a triplet.
fst3 :: (a,b,c) -> a
fst3 (x,_,_) = x
-- | Extract the second component of a triplet.
snd3 :: (a,b,c) -> b
snd3 (_,y,_) = y
-- | Extract the third component of a triplet.
trd3 :: (a,b,c) -> c
trd3 (_,_,z) = z
-- | Apply function of 2 arguments to triplets' elements.
liftT2 :: (a -> b -> c) -> (a,a,a) -> (b,b,b) -> (c,c,c)
liftT2 f (x,y,z) (x',y',z') = (f x x', f y y', f z z')
-- | Encode forbidden file names with trigraphs and substitutions
fixname :: String -> String
fixname "" = "нет имени"
fixname name = concatMap tr name
where tr c = fromMaybe [c] $ lookup c fixnameTable
-- | Inverse of 'fixname'. Hopefully (unfixname . fixname == id).
unfixname :: String -> String
unfixname "нет имени" = ""
unfixname name = unescape name
where unescape [] = []
unescape s@('_':_:_:rest) =
let esc = take 3 s
unesc = fromMaybe esc . lookup esc $ unfixnameTable
-- ^^^ leave as is if name is incorrect
in unesc ++ (unescape rest)
unescape (x:rest) = x:(unescape rest)
-- Symbols forbidden in WinXP filenames: \ / : * ? " < > |
fixnameTable :: [(Char,String)]
fixnameTable =
[ ( '\\', "_Z_" )
, ( '/', "_%_" )
, ( ':', "_=_" )
, ( '*', "_x_" )
, ( '?', "_7_" )
, ( '"', "_'_" )
, ( '<', "_(_" )
, ( '>', "_)_" )
, ( '|', "_I_" )
, ( '_', "___" ) ]
unfixnameTable :: [(String,String)]
unfixnameTable = map (sndSingleton . swap) fixnameTable
where swap (k,v) = (v,k)
sndSingleton (x,y) = (x,[y])
-- | Debug tracing. To be used
dbg :: String -> Bool
#ifdef DEBUGBUILD
dbg msg = daemonTrace (encodeString msg) False
#else
dbg _ = False
#endif
-- | Debug tracing.
trace' :: (Show a) => a -> a
#ifdef DEBUGBUILD
trace' x = daemonTrace (show x) x
#else
trace' = id
#endif
#ifdef DEBUGBUILD
{-# NOINLINE daemonTrace #-}
-- | daemonTrace is a replacement for Debug.Trace.trace.
daemonTrace :: String -- ^ log message
-> a -> a
daemonTrace msg value = unsafePerformIO $ do
debugM rootLoggerName msg
return value
#endif
showL :: String -> [String] -> String
showL "" xs = "[" ++ (intercalate ", " xs) ++ "]"
showL name xs = name ++ " = " ++ (showL "" xs)
showL' :: [String] -> String
showL' = showL ""
stub :: anytype
stub = undefined