text-icu (empty) → 0.1
raw patch · 11 files changed
+1065/−0 lines, 11 filesdep +basedep +bytestringdep +textsetup-changed
Dependencies added: base, bytestring, text
Files
- Data/Text/ICU/Converter.hs +235/−0
- Data/Text/ICU/Converter/Internal.hs +50/−0
- Data/Text/ICU/Error.hsc +275/−0
- Data/Text/ICU/Error/Internal.hs +80/−0
- Data/Text/ICU/Internal.hs +24/−0
- Data/Text/ICU/Normalizer.hsc +298/−0
- LICENSE +26/−0
- README +31/−0
- Setup.lhs +3/−0
- cbits/text_icu.c +8/−0
- text-icu.cabal +35/−0
+ Data/Text/ICU/Converter.hs view
@@ -0,0 +1,235 @@+{-# LANGUAGE CPP, ForeignFunctionInterface #-}+-- |+-- Module : Data.Text.ICU.Converter+-- Copyright : (c) Bryan O'Sullivan 2009+--+-- License : BSD-style+-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : GHC+--+-- Character set conversion functions for Unicode, implemented as+-- bindings to the International Components for Unicode (ICU)+-- libraries.++module Data.Text.ICU.Converter+ (+ -- * Character set conversion+ Converter+ -- ** Basic functions+ , open+ , fromUnicode+ , toUnicode+ -- ** Converter metadata+ , getName+ , usesFallback+ , setFallback+ , isAmbiguous+ -- * Functions for controlling global behavior+ , getDefaultName+ , setDefaultName+ -- * Miscellaneous functions+ , compareNames+ , aliases+ -- * Metadata+ , converterNames+ , standardNames+ ) where++import Data.ByteString.Internal (ByteString, createAndTrim)+import Data.ByteString.Unsafe (unsafeUseAsCStringLen)+import Data.Int (Int32)+import Data.Text (Text)+import Data.Text.Foreign (fromPtr, lengthWord16, useAsPtr)+import Data.Text.ICU.Converter.Internal+import Data.Text.ICU.Error.Internal (UErrorCode, handleError)+import Data.Word (Word16)+import Foreign.C.String (CString, peekCString, withCString)+import Foreign.C.Types (CInt)+import Foreign.ForeignPtr (newForeignPtr)+import Foreign.Marshal.Array (allocaArray)+import Foreign.Ptr (FunPtr, Ptr, castPtr, nullPtr)+import System.IO.Unsafe (unsafePerformIO)+import Data.Text.ICU.Internal (UBool, UChar, asBool, asOrdering)++-- | Do a fuzzy compare of two converter/alias names. The comparison+-- is case-insensitive, ignores leading zeroes if they are not+-- followed by further digits, and ignores all but letters and digits.+-- Thus the strings @\"UTF-8\"@, @\"utf_8\"@, @\"u*T\@f08\"@ and+-- @\"Utf 8\"@ are exactly equivalent. See section 1.4, Charset Alias+-- Matching in Unicode Technical Standard #22 at+-- <http://www.unicode.org/reports/tr22/>+compareNames :: String -> String -> Ordering+compareNames a b =+ unsafePerformIO . withCString a $ \aptr ->+ fmap asOrdering . withCString b $ ucnv_compareNames aptr++-- | Create a 'Converter' with the name of a coded character set+-- specified as a string. The actual name will be resolved with the+-- alias file using a case-insensitive string comparison that ignores+-- leading zeroes and all non-alphanumeric characters. E.g., the+-- names @\"UTF8\"@, @\"utf-8\"@, @\"u*T\@f08\"@ and @\"Utf 8\"@ are+-- all equivalent (see also 'compareNames'). If an empty string is+-- passed for the converter name, it will create one with the+-- 'getDefaultName' return value.+--+-- A converter name may contain options like a locale specification to+-- control the specific behavior of the newly instantiated converter.+-- The meaning of the options depends on the particular converter. If+-- an option is not defined for or recognized by a given converter,+-- then it is ignored.+--+-- Options are appended to the converter name string, with a comma+-- between the name and the first option and also between adjacent+-- options.+--+-- If the alias is ambiguous, then the preferred converter is used.+--+-- The conversion behavior and names can vary between platforms. ICU+-- may convert some characters differently from other+-- platforms. Details on this topic are in the ICU User's Guide at+-- <http://icu-project.org/userguide/conversion.html>. Aliases+-- starting with a @\"cp\"@ prefix have no specific meaning other than+-- its an alias starting with the letters @\"cp\"@. Please do not+-- associate any meaning to these aliases.+open :: String -> IO Converter+open name =+ fmap Converter . newForeignPtr ucnv_close =<< named (handleError . ucnv_open)+ where named act+ | null name = act nullPtr+ | otherwise = withCString name act++-- | Convert the Unicode string into a codepage string using the given+-- converter.+fromUnicode :: Converter -> Text -> IO ByteString+fromUnicode cnv t =+ useAsPtr t $ \tptr tlen ->+ withConverter cnv $ \cptr -> do+ let capacity = fromIntegral . max_bytes_for_string cptr . fromIntegral $+ lengthWord16 t+ createAndTrim (fromIntegral capacity) $ \sptr ->+ fmap fromIntegral . handleError $+ ucnv_fromUChars cptr (castPtr sptr) capacity tptr (fromIntegral tlen)++-- | Convert the codepage string into a Unicode string using the given+-- converter.+toUnicode :: Converter -> ByteString -> IO Text+toUnicode cnv bs =+ unsafeUseAsCStringLen bs $ \(sptr, slen) ->+ withConverter cnv $ \cptr -> do+ let capacity = slen * 2+ allocaArray capacity $ \tptr -> + fromPtr tptr =<< (fmap fromIntegral . handleError $+ ucnv_toUChars cptr tptr (fromIntegral capacity) sptr+ (fromIntegral slen))++-- | Determines whether the converter uses fallback mappings or not.+-- This flag has restrictions; see 'setFallback'.+usesFallback :: Converter -> IO Bool+usesFallback cnv = asBool `fmap` withConverter cnv ucnv_usesFallback++-- | Sets the converter to use fallback mappings or not. Regardless+-- of this flag, the converter will always use fallbacks from Unicode+-- Private Use code points, as well as reverse fallbacks (to Unicode).+-- For details see \".ucm File Format\" in the Conversion Data chapter+-- of the ICU User Guide:+-- <http://www.icu-project.org/userguide/conversion-data.html#ucmformat>+setFallback :: Converter -> Bool -> IO ()+setFallback cnv flag =+ withConverter cnv $ \p -> (ucnv_setFallback p (fromIntegral (fromEnum flag)))++-- | Returns the current default converter name. If you want to 'open'+-- a default converter, you do not need to use this function. It is+-- faster to pass the empty string to 'open' the default converter.+getDefaultName :: IO String+getDefaultName = peekCString =<< ucnv_getDefaultName++-- | Indicates whether the converter contains ambiguous mappings of+-- the same character or not.+isAmbiguous :: Converter -> Bool+isAmbiguous cnv = asBool . unsafePerformIO $ withConverter cnv ucnv_isAmbiguous++-- | Sets the current default converter name. If this function needs+-- to be called, it should be called during application+-- initialization. Most of the time, the results from 'getDefaultName'+-- or 'open' with an empty string argument is sufficient for your+-- application.+--+-- /Note/: this function is not thread safe. /Do not/ call this+-- function when /any/ ICU function is being used from more than one+-- thread!+setDefaultName :: String -> IO ()+setDefaultName s = withCString s $ ucnv_setDefaultName++-- | A list of the canonical names of all available converters.+converterNames :: [String]+{-# NOINLINE converterNames #-}+converterNames = unsafePerformIO $+ mapM ((peekCString =<<) . ucnv_getAvailableName) [0..ucnv_countAvailable-1]++-- | The list of supported standard names.+standardNames :: [String]+{-# NOINLINE standardNames #-}+standardNames = filter (not . null) . unsafePerformIO $+ mapM ((peekCString =<<) . handleError . ucnv_getStandard) [0..ucnv_countStandards-1]++-- | Return the aliases for a given converter or alias name.+aliases :: String -> [String]+aliases name = unsafePerformIO . withCString name $ \ptr -> do+ count <- ucnv_countAliases ptr+ if count == 0+ then return []+ else mapM ((peekCString =<<) . handleError . ucnv_getAlias ptr) [0..count-1]++foreign import ccall unsafe "unicode/ucnv.h ucnv_open_4_0" ucnv_open+ :: CString -> Ptr UErrorCode -> IO (Ptr UConverter)++foreign import ccall unsafe "unicode/ucnv.h &ucnv_close_4_0" ucnv_close+ :: FunPtr (Ptr UConverter -> IO ())++foreign import ccall unsafe "__get_max_bytes_for_string" max_bytes_for_string+ :: Ptr UConverter -> CInt -> CInt++foreign import ccall unsafe "unicode/ucnv.h ucnv_toUChars_4_0" ucnv_toUChars+ :: Ptr UConverter -> Ptr UChar -> Int32 -> CString -> Int32+ -> Ptr UErrorCode -> IO Int32++foreign import ccall unsafe "unicode/ucnv.h ucnv_fromUChars_4_0" ucnv_fromUChars+ :: Ptr UConverter -> CString -> Int32 -> Ptr UChar -> Int32+ -> Ptr UErrorCode -> IO Int32++foreign import ccall unsafe "unicode/ucnv.h ucnv_compareNames_4_0" ucnv_compareNames+ :: CString -> CString -> IO CInt++foreign import ccall unsafe "unicode/ucnv.h ucnv_getDefaultName_4_0" ucnv_getDefaultName+ :: IO CString++foreign import ccall unsafe "unicode/ucnv.h ucnv_setDefaultName_4_0" ucnv_setDefaultName+ :: CString -> IO ()++foreign import ccall unsafe "unicode/ucnv.h ucnv_countAvailable_4_0" ucnv_countAvailable+ :: Int32++foreign import ccall unsafe "unicode/ucnv.h ucnv_getAvailableName_4_0" ucnv_getAvailableName+ :: Int32 -> IO CString++foreign import ccall unsafe "unicode/ucnv.h ucnv_countAliases_4_0" ucnv_countAliases+ :: CString -> IO Word16++foreign import ccall unsafe "unicode/ucnv.h ucnv_getAlias_4_0" ucnv_getAlias+ :: CString -> Word16 -> Ptr UErrorCode -> IO CString++foreign import ccall unsafe "unicode/ucnv.h ucnv_countStandards_4_0" ucnv_countStandards+ :: Word16++foreign import ccall unsafe "unicode/ucnv.h ucnv_getStandard_4_0" ucnv_getStandard+ :: Word16 -> Ptr UErrorCode -> IO CString++foreign import ccall unsafe "unicode/ucnv.h ucnv_usesFallback_4_0" ucnv_usesFallback+ :: Ptr UConverter -> IO UBool++foreign import ccall unsafe "unicode/ucnv.h ucnv_setFallback_4_0" ucnv_setFallback+ :: Ptr UConverter -> UBool -> IO ()++foreign import ccall unsafe "unicode/ucnv.h ucnv_isAmbiguous_4_0" ucnv_isAmbiguous+ :: Ptr UConverter -> IO UBool
+ Data/Text/ICU/Converter/Internal.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE DeriveDataTypeable, EmptyDataDecls, ForeignFunctionInterface #-}+-- |+-- Module : Data.Text.ICU.Converter.Internal+-- Copyright : (c) Bryan O'Sullivan 2009+--+-- License : BSD-style+-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : GHC+--+-- Low-level character set types and functions.++module Data.Text.ICU.Converter.Internal+ (+ Converter(..)+ , UConverter+ , getName+ , withConverter+ ) where++import Data.Text.ICU.Error.Internal (UErrorCode, handleError)+import Data.Typeable (Typeable)+import Foreign.C.String (CString, peekCString)+import Foreign.ForeignPtr (ForeignPtr, withForeignPtr)+import Foreign.Ptr (Ptr)+import System.IO.Unsafe (unsafePerformIO)++data UConverter++-- | Character set converter type. /Note/: this structure is not+-- thread safe. It is /not/ safe to use value of this type+-- simultaneously from multiple threads.+data Converter = Converter {-# UNPACK #-} !(ForeignPtr UConverter)+ deriving (Eq, Typeable)++instance Show Converter where+ show c = "Converter " ++ show (getName c)++withConverter :: Converter -> (Ptr UConverter -> IO a) -> IO a+{-# INLINE withConverter #-}+withConverter (Converter cnv) action = withForeignPtr cnv action++-- | Gets the internal, canonical name of the converter.+getName :: Converter -> String+getName cnv = unsafePerformIO .+ withConverter cnv $ \ptr ->+ peekCString =<< handleError (ucnv_getName ptr)++foreign import ccall unsafe "unicode/ucnv.h ucnv_getName_4_0" ucnv_getName+ :: Ptr UConverter -> Ptr UErrorCode -> IO CString
+ Data/Text/ICU/Error.hsc view
@@ -0,0 +1,275 @@+module Data.Text.ICU.Error+ (+ -- * Types+ ErrorCode,++ -- * Functions+ isSuccess,+ isFailure,+ errorName,++ -- * Warnings+ u_USING_FALLBACK_WARNING,+ u_USING_DEFAULT_WARNING,+ u_SAFECLONE_ALLOCATED_WARNING,+ u_STATE_OLD_WARNING,+ u_STRING_NOT_TERMINATED_WARNING,+ u_SORT_KEY_TOO_SHORT_WARNING,+ u_AMBIGUOUS_ALIAS_WARNING,+ u_DIFFERENT_UCA_VERSION,++ -- * Errors+ u_ILLEGAL_ARGUMENT_ERROR,+ u_MISSING_RESOURCE_ERROR,+ u_INVALID_FORMAT_ERROR,+ u_FILE_ACCESS_ERROR,+ u_INTERNAL_PROGRAM_ERROR,+ u_MESSAGE_PARSE_ERROR,+ u_MEMORY_ALLOCATION_ERROR,+ u_INDEX_OUTOFBOUNDS_ERROR,+ u_PARSE_ERROR,+ u_INVALID_CHAR_FOUND,+ u_TRUNCATED_CHAR_FOUND,+ u_ILLEGAL_CHAR_FOUND,+ u_INVALID_TABLE_FORMAT,+ u_INVALID_TABLE_FILE,+ u_BUFFER_OVERFLOW_ERROR,+ u_UNSUPPORTED_ERROR,+ u_RESOURCE_TYPE_MISMATCH,+ u_ILLEGAL_ESCAPE_SEQUENCE,+ u_UNSUPPORTED_ESCAPE_SEQUENCE,+ u_NO_SPACE_AVAILABLE,+ u_CE_NOT_FOUND_ERROR,+ u_PRIMARY_TOO_LONG_ERROR,+ u_STATE_TOO_OLD_ERROR,+ u_TOO_MANY_ALIASES_ERROR,+ u_ENUM_OUT_OF_SYNC_ERROR,+ u_INVARIANT_CONVERSION_ERROR,+ u_INVALID_STATE_ERROR,+ u_COLLATOR_VERSION_MISMATCH,+ u_USELESS_COLLATOR_ERROR,+ u_NO_WRITE_PERMISSION,++ -- ** Transliterator errors+ u_BAD_VARIABLE_DEFINITION,+ u_MALFORMED_RULE,+ u_MALFORMED_SET,+ u_MALFORMED_UNICODE_ESCAPE,+ u_MALFORMED_VARIABLE_DEFINITION,+ u_MALFORMED_VARIABLE_REFERENCE,+ u_MISPLACED_CURSOR_OFFSET,+ u_MISPLACED_QUANTIFIER,+ u_MISSING_OPERATOR,+ u_MULTIPLE_ANTE_CONTEXTS,+ u_MULTIPLE_CURSORS,+ u_MULTIPLE_POST_CONTEXTS,+ u_TRAILING_BACKSLASH,+ u_UNDEFINED_SEGMENT_REFERENCE,+ u_UNDEFINED_VARIABLE,+ u_UNQUOTED_SPECIAL,+ u_UNTERMINATED_QUOTE,+ u_RULE_MASK_ERROR,+ u_MISPLACED_COMPOUND_FILTER,+ u_MULTIPLE_COMPOUND_FILTERS,+ u_INVALID_RBT_SYNTAX,+ u_MALFORMED_PRAGMA,+ u_UNCLOSED_SEGMENT,+ u_VARIABLE_RANGE_EXHAUSTED,+ u_VARIABLE_RANGE_OVERLAP,+ u_ILLEGAL_CHARACTER,+ u_INTERNAL_TRANSLITERATOR_ERROR,+ u_INVALID_ID,+ u_INVALID_FUNCTION,++ -- ** Formatting API parsing errors+ u_UNEXPECTED_TOKEN,+ u_MULTIPLE_DECIMAL_SEPARATORS,+ u_MULTIPLE_EXPONENTIAL_SYMBOLS,+ u_MALFORMED_EXPONENTIAL_PATTERN,+ u_MULTIPLE_PERCENT_SYMBOLS,+ u_MULTIPLE_PERMILL_SYMBOLS,+ u_MULTIPLE_PAD_SPECIFIERS,+ u_PATTERN_SYNTAX_ERROR,+ u_ILLEGAL_PAD_POSITION,+ u_UNMATCHED_BRACES,+ u_ARGUMENT_TYPE_MISMATCH,+ u_DUPLICATE_KEYWORD,+ u_UNDEFINED_KEYWORD,+ u_DEFAULT_KEYWORD_MISSING,++ -- ** Break iterator errors+ u_BRK_INTERNAL_ERROR,+ u_BRK_HEX_DIGITS_EXPECTED,+ u_BRK_SEMICOLON_EXPECTED,+ u_BRK_RULE_SYNTAX,+ u_BRK_UNCLOSED_SET,+ u_BRK_ASSIGN_ERROR,+ u_BRK_VARIABLE_REDFINITION,+ u_BRK_MISMATCHED_PAREN,+ u_BRK_NEW_LINE_IN_QUOTED_STRING,+ u_BRK_UNDEFINED_VARIABLE,+ u_BRK_INIT_ERROR,+ u_BRK_RULE_EMPTY_SET,+ u_BRK_UNRECOGNIZED_OPTION,+ u_BRK_MALFORMED_RULE_TAG,++ -- ** Regular expression errors+ u_REGEX_INTERNAL_ERROR,+ u_REGEX_RULE_SYNTAX,+ u_REGEX_INVALID_STATE,+ u_REGEX_BAD_ESCAPE_SEQUENCE,+ u_REGEX_PROPERTY_SYNTAX,+ u_REGEX_UNIMPLEMENTED,+ u_REGEX_MISMATCHED_PAREN,+ u_REGEX_NUMBER_TOO_BIG,+ u_REGEX_BAD_INTERVAL,+ u_REGEX_MAX_LT_MIN,+ u_REGEX_INVALID_BACK_REF,+ u_REGEX_INVALID_FLAG,+ u_REGEX_SET_CONTAINS_STRING,+ u_REGEX_OCTAL_TOO_BIG,+ u_REGEX_INVALID_RANGE,+ u_REGEX_STACK_OVERFLOW,+ u_REGEX_TIME_OUT,+ u_REGEX_STOPPED_BY_CALLER,++ -- ** IDNA errors+ u_IDNA_PROHIBITED_ERROR,+ u_IDNA_UNASSIGNED_ERROR,+ u_IDNA_CHECK_BIDI_ERROR,+ u_IDNA_STD3_ASCII_RULES_ERROR,+ u_IDNA_ACE_PREFIX_ERROR,+ u_IDNA_VERIFICATION_ERROR,+ u_IDNA_LABEL_TOO_LONG_ERROR,+ u_IDNA_ZERO_LENGTH_LABEL_ERROR,+ u_IDNA_DOMAIN_NAME_TOO_LONG_ERROR+ ) where++#include <unicode/utypes.h>++import Data.Text.ICU.Error.Internal++#{enum ErrorCode, ErrorCode,+ u_USING_FALLBACK_WARNING = U_USING_FALLBACK_WARNING,+ u_USING_DEFAULT_WARNING = U_USING_DEFAULT_WARNING, + u_SAFECLONE_ALLOCATED_WARNING = U_SAFECLONE_ALLOCATED_WARNING, + u_STATE_OLD_WARNING = U_STATE_OLD_WARNING, + u_STRING_NOT_TERMINATED_WARNING = U_STRING_NOT_TERMINATED_WARNING,+ u_SORT_KEY_TOO_SHORT_WARNING = U_SORT_KEY_TOO_SHORT_WARNING, + u_AMBIGUOUS_ALIAS_WARNING = U_AMBIGUOUS_ALIAS_WARNING, + u_DIFFERENT_UCA_VERSION = U_DIFFERENT_UCA_VERSION, + u_ILLEGAL_ARGUMENT_ERROR = U_ILLEGAL_ARGUMENT_ERROR, + u_MISSING_RESOURCE_ERROR = U_MISSING_RESOURCE_ERROR, + u_INVALID_FORMAT_ERROR = U_INVALID_FORMAT_ERROR, + u_FILE_ACCESS_ERROR = U_FILE_ACCESS_ERROR, + u_INTERNAL_PROGRAM_ERROR = U_INTERNAL_PROGRAM_ERROR, + u_MESSAGE_PARSE_ERROR = U_MESSAGE_PARSE_ERROR, + u_MEMORY_ALLOCATION_ERROR = U_MEMORY_ALLOCATION_ERROR, + u_INDEX_OUTOFBOUNDS_ERROR = U_INDEX_OUTOFBOUNDS_ERROR, + u_PARSE_ERROR = U_PARSE_ERROR, + u_INVALID_CHAR_FOUND = U_INVALID_CHAR_FOUND, + u_TRUNCATED_CHAR_FOUND = U_TRUNCATED_CHAR_FOUND, + u_ILLEGAL_CHAR_FOUND = U_ILLEGAL_CHAR_FOUND, + u_INVALID_TABLE_FORMAT = U_INVALID_TABLE_FORMAT, + u_INVALID_TABLE_FILE = U_INVALID_TABLE_FILE, + u_BUFFER_OVERFLOW_ERROR = U_BUFFER_OVERFLOW_ERROR, + u_UNSUPPORTED_ERROR = U_UNSUPPORTED_ERROR, + u_RESOURCE_TYPE_MISMATCH = U_RESOURCE_TYPE_MISMATCH, + u_ILLEGAL_ESCAPE_SEQUENCE = U_ILLEGAL_ESCAPE_SEQUENCE, + u_UNSUPPORTED_ESCAPE_SEQUENCE = U_UNSUPPORTED_ESCAPE_SEQUENCE, + u_NO_SPACE_AVAILABLE = U_NO_SPACE_AVAILABLE, + u_CE_NOT_FOUND_ERROR = U_CE_NOT_FOUND_ERROR, + u_PRIMARY_TOO_LONG_ERROR = U_PRIMARY_TOO_LONG_ERROR, + u_STATE_TOO_OLD_ERROR = U_STATE_TOO_OLD_ERROR, + u_TOO_MANY_ALIASES_ERROR = U_TOO_MANY_ALIASES_ERROR, + u_ENUM_OUT_OF_SYNC_ERROR = U_ENUM_OUT_OF_SYNC_ERROR, + u_INVARIANT_CONVERSION_ERROR = U_INVARIANT_CONVERSION_ERROR, + u_INVALID_STATE_ERROR = U_INVALID_STATE_ERROR, + u_COLLATOR_VERSION_MISMATCH = U_COLLATOR_VERSION_MISMATCH, + u_USELESS_COLLATOR_ERROR = U_USELESS_COLLATOR_ERROR, + u_NO_WRITE_PERMISSION = U_NO_WRITE_PERMISSION, + u_BAD_VARIABLE_DEFINITION = U_BAD_VARIABLE_DEFINITION,+ u_MALFORMED_RULE = U_MALFORMED_RULE,+ u_MALFORMED_SET = U_MALFORMED_SET,+ u_MALFORMED_UNICODE_ESCAPE = U_MALFORMED_UNICODE_ESCAPE,+ u_MALFORMED_VARIABLE_DEFINITION = U_MALFORMED_VARIABLE_DEFINITION,+ u_MALFORMED_VARIABLE_REFERENCE = U_MALFORMED_VARIABLE_REFERENCE,+ u_MISPLACED_CURSOR_OFFSET = U_MISPLACED_CURSOR_OFFSET,+ u_MISPLACED_QUANTIFIER = U_MISPLACED_QUANTIFIER,+ u_MISSING_OPERATOR = U_MISSING_OPERATOR,+ u_MULTIPLE_ANTE_CONTEXTS = U_MULTIPLE_ANTE_CONTEXTS,+ u_MULTIPLE_CURSORS = U_MULTIPLE_CURSORS,+ u_MULTIPLE_POST_CONTEXTS = U_MULTIPLE_POST_CONTEXTS,+ u_TRAILING_BACKSLASH = U_TRAILING_BACKSLASH,+ u_UNDEFINED_SEGMENT_REFERENCE = U_UNDEFINED_SEGMENT_REFERENCE,+ u_UNDEFINED_VARIABLE = U_UNDEFINED_VARIABLE,+ u_UNQUOTED_SPECIAL = U_UNQUOTED_SPECIAL,+ u_UNTERMINATED_QUOTE = U_UNTERMINATED_QUOTE,+ u_RULE_MASK_ERROR = U_RULE_MASK_ERROR,+ u_MISPLACED_COMPOUND_FILTER = U_MISPLACED_COMPOUND_FILTER,+ u_MULTIPLE_COMPOUND_FILTERS = U_MULTIPLE_COMPOUND_FILTERS,+ u_INVALID_RBT_SYNTAX = U_INVALID_RBT_SYNTAX,+ u_MALFORMED_PRAGMA = U_MALFORMED_PRAGMA,+ u_UNCLOSED_SEGMENT = U_UNCLOSED_SEGMENT,+ u_VARIABLE_RANGE_EXHAUSTED = U_VARIABLE_RANGE_EXHAUSTED,+ u_VARIABLE_RANGE_OVERLAP = U_VARIABLE_RANGE_OVERLAP,+ u_ILLEGAL_CHARACTER = U_ILLEGAL_CHARACTER,+ u_INTERNAL_TRANSLITERATOR_ERROR = U_INTERNAL_TRANSLITERATOR_ERROR,+ u_INVALID_ID = U_INVALID_ID,+ u_INVALID_FUNCTION = U_INVALID_FUNCTION,+ u_UNEXPECTED_TOKEN = U_UNEXPECTED_TOKEN, + u_MULTIPLE_DECIMAL_SEPARATORS = U_MULTIPLE_DECIMAL_SEPARATORS,+ u_MULTIPLE_EXPONENTIAL_SYMBOLS = U_MULTIPLE_EXPONENTIAL_SYMBOLS,+ u_MALFORMED_EXPONENTIAL_PATTERN = U_MALFORMED_EXPONENTIAL_PATTERN,+ u_MULTIPLE_PERCENT_SYMBOLS = U_MULTIPLE_PERCENT_SYMBOLS,+ u_MULTIPLE_PERMILL_SYMBOLS = U_MULTIPLE_PERMILL_SYMBOLS,+ u_MULTIPLE_PAD_SPECIFIERS = U_MULTIPLE_PAD_SPECIFIERS,+ u_PATTERN_SYNTAX_ERROR = U_PATTERN_SYNTAX_ERROR,+ u_ILLEGAL_PAD_POSITION = U_ILLEGAL_PAD_POSITION,+ u_UNMATCHED_BRACES = U_UNMATCHED_BRACES,+ u_ARGUMENT_TYPE_MISMATCH = U_ARGUMENT_TYPE_MISMATCH,+ u_DUPLICATE_KEYWORD = U_DUPLICATE_KEYWORD,+ u_UNDEFINED_KEYWORD = U_UNDEFINED_KEYWORD,+ u_DEFAULT_KEYWORD_MISSING = U_DEFAULT_KEYWORD_MISSING,+ u_BRK_INTERNAL_ERROR = U_BRK_INTERNAL_ERROR, + u_BRK_HEX_DIGITS_EXPECTED = U_BRK_HEX_DIGITS_EXPECTED,+ u_BRK_SEMICOLON_EXPECTED = U_BRK_SEMICOLON_EXPECTED,+ u_BRK_RULE_SYNTAX = U_BRK_RULE_SYNTAX,+ u_BRK_UNCLOSED_SET = U_BRK_UNCLOSED_SET,+ u_BRK_ASSIGN_ERROR = U_BRK_ASSIGN_ERROR,+ u_BRK_VARIABLE_REDFINITION = U_BRK_VARIABLE_REDFINITION,+ u_BRK_MISMATCHED_PAREN = U_BRK_MISMATCHED_PAREN,+ u_BRK_NEW_LINE_IN_QUOTED_STRING = U_BRK_NEW_LINE_IN_QUOTED_STRING,+ u_BRK_UNDEFINED_VARIABLE = U_BRK_UNDEFINED_VARIABLE,+ u_BRK_INIT_ERROR = U_BRK_INIT_ERROR,+ u_BRK_RULE_EMPTY_SET = U_BRK_RULE_EMPTY_SET,+ u_BRK_UNRECOGNIZED_OPTION = U_BRK_UNRECOGNIZED_OPTION,+ u_BRK_MALFORMED_RULE_TAG = U_BRK_MALFORMED_RULE_TAG,+ u_REGEX_INTERNAL_ERROR = U_REGEX_INTERNAL_ERROR, + u_REGEX_RULE_SYNTAX = U_REGEX_RULE_SYNTAX,+ u_REGEX_INVALID_STATE = U_REGEX_INVALID_STATE,+ u_REGEX_BAD_ESCAPE_SEQUENCE = U_REGEX_BAD_ESCAPE_SEQUENCE,+ u_REGEX_PROPERTY_SYNTAX = U_REGEX_PROPERTY_SYNTAX,+ u_REGEX_UNIMPLEMENTED = U_REGEX_UNIMPLEMENTED,+ u_REGEX_MISMATCHED_PAREN = U_REGEX_MISMATCHED_PAREN,+ u_REGEX_NUMBER_TOO_BIG = U_REGEX_NUMBER_TOO_BIG,+ u_REGEX_BAD_INTERVAL = U_REGEX_BAD_INTERVAL,+ u_REGEX_MAX_LT_MIN = U_REGEX_MAX_LT_MIN,+ u_REGEX_INVALID_BACK_REF = U_REGEX_INVALID_BACK_REF,+ u_REGEX_INVALID_FLAG = U_REGEX_INVALID_FLAG,+ u_REGEX_SET_CONTAINS_STRING = U_REGEX_SET_CONTAINS_STRING,+ u_REGEX_OCTAL_TOO_BIG = U_REGEX_OCTAL_TOO_BIG,+ u_REGEX_INVALID_RANGE = U_REGEX_INVALID_RANGE,+ u_REGEX_STACK_OVERFLOW = U_REGEX_STACK_OVERFLOW,+ u_REGEX_TIME_OUT = U_REGEX_TIME_OUT,+ u_REGEX_STOPPED_BY_CALLER = U_REGEX_STOPPED_BY_CALLER,+ u_IDNA_PROHIBITED_ERROR = U_IDNA_PROHIBITED_ERROR,+ u_IDNA_UNASSIGNED_ERROR = U_IDNA_UNASSIGNED_ERROR,+ u_IDNA_CHECK_BIDI_ERROR = U_IDNA_CHECK_BIDI_ERROR,+ u_IDNA_STD3_ASCII_RULES_ERROR = U_IDNA_STD3_ASCII_RULES_ERROR,+ u_IDNA_ACE_PREFIX_ERROR = U_IDNA_ACE_PREFIX_ERROR,+ u_IDNA_VERIFICATION_ERROR = U_IDNA_VERIFICATION_ERROR,+ u_IDNA_LABEL_TOO_LONG_ERROR = U_IDNA_LABEL_TOO_LONG_ERROR,+ u_IDNA_ZERO_LENGTH_LABEL_ERROR = U_IDNA_ZERO_LENGTH_LABEL_ERROR,+ u_IDNA_DOMAIN_NAME_TOO_LONG_ERROR = U_IDNA_DOMAIN_NAME_TOO_LONG_ERROR+}
+ Data/Text/ICU/Error/Internal.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE DeriveDataTypeable, ForeignFunctionInterface #-}++module Data.Text.ICU.Error.Internal+ (+ -- * Types+ ErrorCode(..)+ -- ** Low-level types+ , UErrorCode+ -- * Functions+ , isFailure+ , isSuccess+ , errorName+ , handleError+ , throwOnError+ , withError+ ) where++import Control.Exception+import Foreign.Ptr+import Foreign.Marshal.Alloc+import Data.Typeable (Typeable)+import Foreign.C.String (CString, peekCString)+import Foreign.C.Types (CInt)+import Foreign.Storable+import System.IO.Unsafe (unsafePerformIO)++type UErrorCode = CInt++-- | ICU error code.+newtype ErrorCode = ErrorCode {+ fromErrorCode :: UErrorCode+ } deriving (Eq, Typeable)++instance Show ErrorCode where+ show code = "ErrorCode " ++ errorName code++instance Exception ErrorCode++-- | Indicate whether the given error code is a success.+isSuccess :: ErrorCode -> Bool+{-# INLINE isSuccess #-}+isSuccess = (<= 0) . fromErrorCode++-- | Indicate whether the given error code is a failure.+isFailure :: ErrorCode -> Bool+{-# INLINE isFailure #-}+isFailure = (> 0) . fromErrorCode++-- | Throw an exception if the given code is actually an error.+throwOnError :: UErrorCode -> IO ()+{-# INLINE throwOnError #-}+throwOnError code = do+ let err = (ErrorCode code)+ if isFailure err+ then throw err+ else return ()++withError :: (Ptr UErrorCode -> IO a) -> IO (ErrorCode, a)+{-# INLINE withError #-}+withError action = alloca $ \errPtr -> do+ poke errPtr 0+ ret <- action errPtr+ err <- peek errPtr+ return (ErrorCode err, ret)++handleError :: (Ptr UErrorCode -> IO a) -> IO a+{-# INLINE handleError #-}+handleError action = alloca $ \errPtr -> do+ poke errPtr 0+ ret <- action errPtr+ throwOnError =<< peek errPtr+ return ret++-- | Return a string representing the name of the given error code.+errorName :: ErrorCode -> String+errorName code = unsafePerformIO $+ peekCString (u_errorName (fromErrorCode code))++foreign import ccall unsafe "unicode/utypes.h u_errorName_4_0" u_errorName+ :: UErrorCode -> CString
+ Data/Text/ICU/Internal.hs view
@@ -0,0 +1,24 @@+module Data.Text.ICU.Internal+ (+ UBool+ , UChar+ , asBool+ , asOrdering+ ) where++import Data.Int (Int8)+import Data.Word (Word16)++type UBool = Int8+type UChar = Word16++asBool :: Integral a => a -> Bool+{-# INLINE asBool #-}+asBool = (/=0)++asOrdering :: Integral a => a -> Ordering+{-# INLINE asOrdering #-}+asOrdering i+ | i < 0 = LT+ | i == 0 = EQ+ | otherwise = GT
+ Data/Text/ICU/Normalizer.hsc view
@@ -0,0 +1,298 @@+{-# LANGUAGE CPP, DeriveDataTypeable, ForeignFunctionInterface,+ GeneralizedNewtypeDeriving #-}+-- |+-- Module : Data.Text.ICU.Normalizer+-- Copyright : (c) Bryan O'Sullivan 2009+--+-- License : BSD-style+-- Maintainer : bos@serpentine.com+-- Stability : experimental+-- Portability : GHC+--+-- Character set normalization functions for Unicode, implemented as+-- bindings to the International Components for Unicode (ICU)+-- libraries.++module Data.Text.ICU.Normalizer+ (+ -- * Unicode normalization API+ -- $api+ NormalizationMode(..)+ -- * Normalization functions+ , normalize+ -- * Normalization checks+ , NormalizationCheckResult(..)+ , quickCheck+ , isNormalized+ -- * Normalization-sensitive comparison+ , CompareOption+ , u_INPUT_IS_FCD+ , u_COMPARE_CODE_POINT_ORDER+ , u_COMPARE_IGNORE_CASE+ , compare+ ) where++#include <unicode/unorm.h>++import Control.Exception (throw)+import Control.Monad (when)+import Data.Text (Text)+import Data.Text.Foreign (fromPtr, useAsPtr)+import Data.Text.ICU.Error (u_BUFFER_OVERFLOW_ERROR)+import Data.Text.ICU.Error.Internal (UErrorCode, isFailure, handleError, withError)+import Data.Text.ICU.Internal (UBool, UChar, asBool, asOrdering)+import Data.Typeable (Typeable)+import Data.Int (Int32)+import Data.Word (Word32)+import Foreign.C.Types (CInt)+import Foreign.Marshal.Array (allocaArray)+import Foreign.Ptr (Ptr)+import System.IO.Unsafe (unsafePerformIO)+import Prelude hiding (compare)+import Data.List (foldl')+import Data.Bits ((.|.))++-- $api+--+-- 'normalize' transforms Unicode text into an equivalent composed or+-- decomposed form, allowing for easier sorting and searching of text.+-- 'normalize' supports the standard normalization forms described in+-- <http://www.unicode.org/unicode/reports/tr15/>,+-- Unicode Standard Annex #15: Unicode Normalization Forms.+--+-- Characters with accents or other adornments can be encoded in+-- several different ways in Unicode. For example, take the character A-acute.+-- In Unicode, this can be encoded as a single character (the+-- \"composed\" form):+--+-- @+-- 00C1 LATIN CAPITAL LETTER A WITH ACUTE+-- @+--+-- or as two separate characters (the \"decomposed\" form):+--+-- @+-- 0041 LATIN CAPITAL LETTER A+-- 0301 COMBINING ACUTE ACCENT+-- @+--+-- To a user of your program, however, both of these sequences should+-- be treated as the same \"user-level\" character \"A with acute+-- accent\". When you are searching or comparing text, you must+-- ensure that these two sequences are treated equivalently. In+-- addition, you must handle characters with more than one accent.+-- Sometimes the order of a character's combining accents is+-- significant, while in other cases accent sequences in different+-- orders are really equivalent.+--+-- Similarly, the string \"ffi\" can be encoded as three separate letters:+--+-- @+-- 0066 LATIN SMALL LETTER F+-- 0066 LATIN SMALL LETTER F+-- 0069 LATIN SMALL LETTER I+-- @+--+-- or as the single character+--+-- @+-- FB03 LATIN SMALL LIGATURE FFI+-- @+--+-- The \"ffi\" ligature is not a distinct semantic character, and+-- strictly speaking it shouldn't be in Unicode at all, but it was+-- included for compatibility with existing character sets that+-- already provided it. The Unicode standard identifies such+-- characters by giving them \"compatibility\" decompositions into the+-- corresponding semantic characters. When sorting and searching, you+-- will often want to use these mappings.+--+-- 'normalize' helps solve these problems by transforming text into+-- the canonical composed and decomposed forms as shown in the first+-- example above. In addition, you can have it perform compatibility+-- decompositions so that you can treat compatibility characters the+-- same as their equivalents. Finally, 'normalize' rearranges accents+-- into the proper canonical order, so that you do not have to worry+-- about accent rearrangement on your own.+--+-- Form 'FCD', \"Fast C or D\", is also designed for collation. It+-- allows to work on strings that are not necessarily normalized with+-- an algorithm (like in collation) that works under \"canonical+-- closure\", i.e., it treats precomposed characters and their+-- decomposed equivalents the same.+--+-- It is not a normalization form because it does not provide for+-- uniqueness of representation. Multiple strings may be canonically+-- equivalent (their NFDs are identical) and may all conform to 'FCD'+-- without being identical themselves.+--+-- The form is defined such that the \"raw decomposition\", the+-- recursive canonical decomposition of each character, results in a+-- string that is canonically ordered. This means that precomposed+-- characters are allowed for as long as their decompositions do not+-- need canonical reordering.+--+-- Its advantage for a process like collation is that all 'NFD' and+-- most 'NFC' texts - and many unnormalized texts - already conform to+-- 'FCD' and do not need to be normalized ('NFD') for such a+-- process. The 'FCD' 'quickCheck' will return 'Yes' for most strings+-- in practice.+--+-- @'normalize' 'FCD'@ may be implemented with 'NFD'.+--+-- For more details on 'FCD' see the collation design document:+-- <http://source.icu-project.org/repos/icu/icuhtml/trunk/design/collation/ICU_collation_design.htm>+--+-- ICU collation performs either 'NFD' or 'FCD' normalization+-- automatically if normalization is turned on for the collator+-- object. Beyond collation and string search, normalized strings may+-- be useful for string equivalence comparisons,+-- transliteration/transcription, unique representations, etc.+--+-- The W3C generally recommends to exchange texts in 'NFC'. Note also+-- that most legacy character encodings use only precomposed forms and+-- often do not encode any combining marks by themselves. For+-- conversion to such character encodings the Unicode text needs to be+-- normalized to 'NFC'. For more usage examples, see the Unicode+-- Standard Annex.++newtype CompareOption = CompareOption {+ fromCompareOption :: Word32+ } deriving (Eq, Typeable)++foldCompareOptions :: [CompareOption] -> Word32+foldCompareOptions = foldl' orO 0+ where a `orO` b = a .|. fromCompareOption b++#{enum CompareOption, CompareOption,+ u_INPUT_IS_FCD = UNORM_INPUT_IS_FCD,+ u_COMPARE_CODE_POINT_ORDER = U_COMPARE_CODE_POINT_ORDER,+ u_COMPARE_IGNORE_CASE = U_COMPARE_IGNORE_CASE+ }++type UNormalizationMode = CInt++data NormalizationMode+ = None -- ^ No decomposition/composition.+ | NFD -- ^ Canonical decomposition.+ | NFKD -- ^ Compatibility decomposition.+ | NFC -- ^ Canonical decomposition followed by canonical composition.+ | NFKC -- ^ Compatibility decomposition followed by canonical composition.+ | FCD -- ^ \"Fast C or D\" form.+ deriving (Eq, Show, Enum, Typeable)+ +toNM :: NormalizationMode -> UNormalizationMode+toNM None = #const UNORM_NONE+toNM NFD = #const UNORM_NFD+toNM NFKD = #const UNORM_NFKD+toNM NFC = #const UNORM_NFC+toNM NFKC = #const UNORM_NFKC+toNM FCD = #const UNORM_FCD++type UNormalizationCheckResult = CInt++data NormalizationCheckResult+ = No -- ^ Text is not normalized.+ | Perhaps -- ^ It cannot be determined whether text is in normalized + -- form without further thorough checks.+ | Yes -- ^ Text is in normalized form.+ deriving (Eq, Show, Enum, Typeable)+ +toNCR :: UNormalizationCheckResult -> NormalizationCheckResult+toNCR (#const UNORM_NO) = No+toNCR (#const UNORM_MAYBE) = Perhaps+toNCR (#const UNORM_YES) = Yes+toNCR _ = error "toNormalizationCheckResult"++-- | Normalize a string according the specified normalization mode.+normalize :: NormalizationMode -> Text -> Text+normalize mode t = unsafePerformIO . useAsPtr t $ \sptr slen ->+ let slen' = fromIntegral slen+ mode' = toNM mode+ loop dlen =+ (either loop return =<<) .+ allocaArray dlen $ \dptr -> do+ (err, newLen) <- withError $+ unorm_normalize sptr slen' mode' 0 dptr (fromIntegral dlen)+ when (isFailure err && err /= u_BUFFER_OVERFLOW_ERROR) $+ throw err+ let newLen' = fromIntegral newLen+ if newLen' > dlen+ then return (Left newLen')+ else Right `fmap` fromPtr dptr newLen'+ in loop slen+ + +-- | Perform an efficient check on a string, to quickly determine if+-- the string is in a particular normalization format.+--+-- A 'Perhaps' result indicates that a more thorough check is+-- required, e.g. with 'isNormalized'. The user may have to put the+-- string in its normalized form and compare the results.+quickCheck :: NormalizationMode -> Text -> NormalizationCheckResult+quickCheck mode t =+ unsafePerformIO . useAsPtr t $ \ptr len ->+ fmap toNCR . handleError $ unorm_quickCheck ptr (fromIntegral len)+ (toNM mode)++-- | Indicate whether a string is in a given normalization form.+--+-- Unlike 'quickCheck', this function returns a definitive result.+-- For 'NFD', 'NFKD', and 'FCD' normalization forms, both functions+-- work in exactly the same ways. For 'NFC' and 'NFKC' forms, where+-- 'quickCheck' may return 'Perhaps', this function will perform+-- further tests to arrive at a definitive result.+isNormalized :: NormalizationMode -> Text -> Bool+isNormalized mode t =+ unsafePerformIO . useAsPtr t $ \ptr len ->+ fmap asBool . handleError $ unorm_isNormalized ptr (fromIntegral len)+ (toNM mode)++-- | Compare two strings for canonical equivalence.+-- Further options include case-insensitive comparison and+-- code point order (as opposed to code unit order).+--+-- Canonical equivalence between two strings is defined as their normalized+-- forms (NFD or NFC) being identical.+-- This function compares strings incrementally instead of normalizing+-- (and optionally case-folding) both strings entirely,+-- improving performance significantly.+--+-- Bulk normalization is only necessary if the strings do not fulfill the FCD+-- conditions. Only in this case, and only if the strings are relatively long,+-- is memory allocated temporarily.+-- For FCD strings and short non-FCD strings there is no memory allocation.+--+-- Options:+--+-- ['u_INPUT_IS_FCD'] Set if the caller knows that both strings fulfill the FCD conditions.+-- If not set, the function will 'quickCheck' for FCD+-- and normalize if necessary.+--+-- ['u_COMPARE_CODE_POINT_ORDER'] Set to choose code point order instead of code unit order.+--+-- ['u_COMPARE_IGNORE_CASE'] Set to compare strings case-insensitively using case folding,+-- instead of case-sensitively.+-- If set, then the following case folding options are used.+compare :: [CompareOption] -> Text -> Text -> Ordering+compare opts a b = unsafePerformIO .+ useAsPtr a $ \aptr alen ->+ useAsPtr b $ \bptr blen ->+ fmap asOrdering . handleError $+ unorm_compare aptr (fromIntegral alen) bptr (fromIntegral blen)+ (foldCompareOptions opts)++foreign import ccall unsafe "unicode/unorm.h unorm_compare_4_0" unorm_compare+ :: Ptr UChar -> Int32 -> Ptr UChar -> Int32 -> Word32+ -> Ptr UErrorCode -> IO Int32++foreign import ccall unsafe "unicode/unorm.h unorm_quickCheck_4_0" unorm_quickCheck+ :: Ptr UChar -> Int32 -> UNormalizationMode -> Ptr UErrorCode+ -> IO UNormalizationCheckResult++foreign import ccall unsafe "unicode/unorm.h unorm_isNormalized_4_0" unorm_isNormalized+ :: Ptr UChar -> Int32 -> UNormalizationMode -> Ptr UErrorCode -> IO UBool++foreign import ccall unsafe "unicode/unorm.h unorm_normalize_4_0" unorm_normalize+ :: Ptr UChar -> Int32 -> UNormalizationMode -> Int32+ -> Ptr UChar -> Int32 -> Ptr UErrorCode -> IO Int32
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright (c) 2009, Bryan O'Sullivan+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README view
@@ -0,0 +1,31 @@+Text-ICU: Comprehensive support for string manipulation+-------------------------------------------------------++This package provides the Data.Text.ICU library, for performing+complex manipulation of Unicode text. It provides features such as+the following:++- Unicode normalization+- Conversion to and from many common and obscure encodings+++Prerequisites+-------------++This library is implemented as bindings to the well-respected ICU+library, which is not included. The version of ICU currently+supported is 4.0.++http://www.icu-project.org/+++Source code+-----------++darcs get http://darcs.serpentine.com/text-icu+++Authors+-------++This library was written by Bryan O'Sullivan.
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell+> import Distribution.Simple+> main = defaultMain
+ cbits/text_icu.c view
@@ -0,0 +1,8 @@+#include "unicode/ucnv.h"++#include <stdint.h>++int __get_max_bytes_for_string(UConverter *cnv, int src_length)+{+ return UCNV_GET_MAX_BYTES_FOR_STRING(src_length, ucnv_getMaxCharSize(cnv));+}
+ text-icu.cabal view
@@ -0,0 +1,35 @@+name: text-icu+version: 0.1+synopsis: Bindings to the ICU library+description: Haskell bindings to the International Components for+ Unicode (ICU) libraries. These libraries provide+ robust and full-featured Unicode services on a wide+ variety of platforms.+maintainer: Bryan O'Sullivan <bos@serpentine.com>+copyright: 2009 Bryan O'Sullivan+category: Data, Text+license: BSD3+license-file: LICENSE+build-type: Simple+cabal-version: >= 1.2+extra-source-files: README++library+ build-depends: base < 5, bytestring, text+ if impl(ghc >= 6.10)+ build-depends: base >= 4++ exposed-modules:+ Data.Text.ICU.Converter+ Data.Text.ICU.Error+ Data.Text.ICU.Normalizer+ other-modules:+ Data.Text.ICU.Converter.Internal+ Data.Text.ICU.Error.Internal+ Data.Text.ICU.Internal+ c-sources: cbits/text_icu.c+ extra-libraries: icui18n icuuc icudata++ ghc-options: -Wall+ if impl(ghc >= 6.8)+ ghc-options: -fwarn-tabs