packages feed

lsfrom-2.0: src/Collate.hs

{-# LANGUAGE ForeignFunctionInterface #-}

-- with help from Gemini 2.0
-- first CString version: https://g.co/gemini/share/5eedf4ddf81e

module Collate (
  before,
  beforeUnsafe,
  ccollate)
where

import Foreign.C.String
import Foreign.C.Types
import System.IO.Unsafe (unsafePerformIO)

-- | Compares two wide strings using the current locale.
--
-- Returns:
--   - A negative integer if the first string is less than the second.
--   - Zero if the two strings are equal.
--   - A positive integer if the first string is greater than the second.
foreign import ccall safe "wcscoll"
  wcscoll :: CWString -> CWString -> CInt

-- | A safe wrapper around 'wcscoll' that takes Haskell String's and
-- handles the conversion to CWString's.
-- Requires that locale (LC_COLLATE) is set correctly.
wcscoll' :: String -> String -> IO CInt
wcscoll' s1 s2 = do
  withCWString s1 $ \cs1 ->
    withCWString s2 $ \cs2 ->
      return $ wcscoll cs1 cs2

-- |  Higher level function that returns an 'Ordering'.
ccollate :: String -> String -> IO Ordering
ccollate s1 s2 = do
  result <- wcscoll' s1 s2
  return $ compare result 0

-- | "ABC" `before` "DEF"
before :: String -> String -> IO Bool
before s1 s2 = do
  res <- ccollate s1 s2
  return $ res == LT

-- | unsafe wrapper
beforeUnsafe :: String -> String -> Bool
beforeUnsafe s1 s2 = unsafePerformIO $ before s1 s2