File: Util.hs

package info (click to toggle)
haskell-options 1.2.1.1-10
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 184 kB
  • sloc: haskell: 2,143; ansic: 91; makefile: 2
file content (64 lines) | stat: -rw-r--r-- 1,914 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
{-# LANGUAGE CPP #-}
{-# LANGUAGE ForeignFunctionInterface #-}

-- |
-- Module: Options.Util
-- License: MIT
module Options.Util where

import           Data.Char (isAlphaNum, isLetter, isUpper)
import qualified Data.Set as Set

#if defined(OPTIONS_ENCODING_UTF8)
import           Data.Char (chr)
import           Data.ByteString.Unsafe (unsafeUseAsCStringLen)
import qualified Data.ByteString.Char8 as Char8
import           Foreign
import           Foreign.C
#endif

stringToGhc704 :: String -> String
#if defined(OPTIONS_ENCODING_UTF8)
stringToGhc704 = decodeUtf8 . Char8.pack

decodeUtf8 :: Char8.ByteString -> String
decodeUtf8 bytes = map (chr . fromIntegral) word32s where
	word32s = unsafePerformIO (unsafeUseAsCStringLen bytes io)
	io (bytesPtr, len) = allocaArray len $ \wordsPtr -> do
		nWords <- c_decodeString (castPtr bytesPtr) wordsPtr (fromIntegral len)
		peekArray (fromIntegral nWords) wordsPtr

foreign import ccall unsafe "hsoptions_decode_string"
	c_decodeString :: Ptr Word8 -> Ptr Word32 -> CInt -> IO CInt
#else
stringToGhc704 = id
#endif

validFieldName :: String -> Bool
validFieldName = valid where
	valid s = case s of
		[] -> False
		c : cs -> validFirst c && all validGeneral cs
	validFirst c = c == '_' || (isLetter c && not (isUpper c))
	validGeneral c = isAlphaNum c || c == '_' || c == '\''

validShortFlag :: Char -> Bool
validShortFlag = isAlphaNum

validLongFlag :: String -> Bool
validLongFlag = valid where
	valid s = case s of
		[] -> False
		c : cs -> validFirst c && all validGeneral cs
	validFirst = isAlphaNum
	validGeneral c = isAlphaNum c || c == '-' || c == '_'

hasDuplicates :: Ord a => [a] -> Bool
hasDuplicates xs = Set.size (Set.fromList xs) /= length xs

mapEither :: (a -> Either err b) -> [a] -> Either err [b]
mapEither fn = loop [] where
	loop acc [] = Right (reverse acc)
	loop acc (a:as) = case fn a of
		Left err -> Left err
		Right b -> loop (b:acc) as