code-page-0.2.1/0000755000000000000000000000000007346545000011527 5ustar0000000000000000code-page-0.2.1/CHANGELOG.md0000755000000000000000000000342707346545000013351 0ustar0000000000000000### 0.2.1 [2021.02.06] * Allow building with `base-4.15` (GHC 9.0) or later on Windows. ## 0.2 [2018.11.13] * Rename the `withCodePageVerbosity` function to `withCodePageOptions` to reflect the fact that its first argument is now an `Options` data type instead of just a `Bool` to represent its verbosity. (The ability to configure verbosity is now controlled through the `chatty` field of `Options`.) * On non-Windows OSes, `withCodePage` (and related functions) now make a best effort guess in converting the supplied `CodePage` to a `TextEncoding` and adjusing the current `TextEncoding` to that one. (For instance, `withCP65001` will adjust the current `TextEncoding` to be `utf8` on non-Windows OSes.) If the supplied `CodePage` does not map to a known `TextEncoding`, these functions will error at runtime on non-Windows OSes. This is a departure from the previous major version of `code-page`, where these functions did not do anything at all on non-Windows OSes. If you would like to recover this old behavior, use `withCodePageOptions defaultOptions{nonWindowsBehavior = NonWindowsDoNothing}`. * `withCodePage` and friends now change the locale encoding (on GHC 7.4 or later) in addition to the encodings for `stdin`, `stdout`, and `stderr`. * Add `withCP1252` and `cp1252` for the Latin1 code page. * Add a `System.IO.CodePage.Internal` module that contains certain internal details (such as the constructors of `Options` and `NonWindowsBehavior`). ### 0.1.3 [2017.03.15] * Fix the build on GHC 7.8 and older ### 0.1.2 [2017.02.20] * Squash minor bug in fixCodePage (the same bug reported in https://github.com/commercialhaskell/stack/pull/3002) ### 0.1.1 [2016.11.09] * Fix the build on non-Intel architectures (thanks, erikd!) ## 0.1 [2016.09.15] * Initial commit. code-page-0.2.1/LICENSE0000644000000000000000000000276307346545000012544 0ustar0000000000000000Copyright (c) 2016-2017, Ryan Scott 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. * Neither the name of Ryan Scott nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. 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. code-page-0.2.1/README.md0000755000000000000000000000256007346545000013014 0ustar0000000000000000# `code-page` [![Hackage](https://img.shields.io/hackage/v/code-page.svg)][Hackage: code-page] [![Hackage Dependencies](https://img.shields.io/hackage-deps/v/code-page.svg)](http://packdeps.haskellers.com/reverse/code-page) [![Haskell Programming Language](https://img.shields.io/badge/language-Haskell-blue.svg)][Haskell.org] [![BSD3 License](http://img.shields.io/badge/license-BSD3-brightgreen.svg)][tl;dr Legal: BSD3] [![Linux build](https://github.com/RyanGlScott/code-page/workflows/Haskell-CI/badge.svg)](https://github.com/RyanGlScott/code-page/actions?query=workflow%3AHaskell-CI) [![Windows build](https://ci.appveyor.com/api/projects/status/kaxqsgm2xx66l2q5?svg=true)](https://ci.appveyor.com/project/RyanGlScott/code-page) [Hackage: code-page]: http://hackage.haskell.org/package/code-page "code-page package on Hackage" [Haskell.org]: http://www.haskell.org "The Haskell Programming Language" [tl;dr Legal: BSD3]: https://tldrlegal.com/license/bsd-3-clause-license-%28revised%29 "BSD 3-Clause License (Revised)" This library provides two modules: * `System.IO.CodePage`: a cross-platform module that exports functions which adjust code pages on Windows, and do nothing on other operating systems. * `System.Win32.CodePage`: On Windows, this exports functions for getting, setting, and analyzing code pages. On other operating systems, this module exports nothing. code-page-0.2.1/Setup.hs0000644000000000000000000000005607346545000013164 0ustar0000000000000000import Distribution.Simple main = defaultMain code-page-0.2.1/code-page.cabal0000644000000000000000000000457307346545000014350 0ustar0000000000000000name: code-page version: 0.2.1 synopsis: Windows code page library for Haskell description: This library provides two modules: . * "System.IO.CodePage": a cross-platform module that exports functions which adjust code pages on Windows, and do nothing on other operating systems. . * "System.Win32.CodePage": On Windows, this exports functions for getting, setting, and analyzing code pages. On other operating systems, this module exports nothing. homepage: https://github.com/RyanGlScott/code-page bug-reports: https://github.com/RyanGlScott/code-page/issues license: BSD3 license-file: LICENSE author: Ryan Scott maintainer: Ryan Scott stability: Provisional copyright: (C) 2016-2017 Ryan Scott category: System build-type: Simple extra-source-files: CHANGELOG.md, README.md, include/*.h cabal-version: >=1.10 tested-with: GHC == 7.0.4 , GHC == 7.2.2 , GHC == 7.4.2 , GHC == 7.6.3 , GHC == 7.8.4 , GHC == 7.10.3 , GHC == 8.0.2 , GHC == 8.2.2 , GHC == 8.4.4 , GHC == 8.6.5 , GHC == 8.8.4 , GHC == 8.10.2 source-repository head type: git location: https://github.com/RyanGlScott/code-page library exposed-modules: System.IO.CodePage System.IO.CodePage.Internal System.Win32.CodePage build-depends: base >= 4.3 && < 5 build-tools: hsc2hs if os(windows) include-dirs: include includes: windows_cconv.h cpp-options: "-DWINDOWS" build-depends: Win32 hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall test-suite tests type: exitcode-stdio-1.0 main-is: Tests.hs build-depends: base >= 4.3 && < 5 , code-page hs-source-dirs: tests default-language: Haskell2010 ghc-options: -Wall -threaded -rtsopts code-page-0.2.1/include/0000755000000000000000000000000007346545000013152 5ustar0000000000000000code-page-0.2.1/include/windows_cconv.h0000755000000000000000000000033307346545000016207 0ustar0000000000000000#ifndef WINDOWS_CCONV_H #define WINDOWS_CCONV_H #if defined(i386_HOST_ARCH) # define WINDOWS_CCONV stdcall #elif defined(x86_64_HOST_ARCH) # define WINDOWS_CCONV ccall #else # error Unknown mingw32 arch #endif #endif code-page-0.2.1/src/System/IO/0000755000000000000000000000000007346545000014111 5ustar0000000000000000code-page-0.2.1/src/System/IO/CodePage.hs0000644000000000000000000001514007346545000016115 0ustar0000000000000000{-# LANGUAGE CPP #-} {-# LANGUAGE NamedFieldPuns #-} {-| Module: System.IO.CodePage Copyright: (C) 2016-2017 Ryan Scott License: BSD-style (see the file LICENSE) Maintainer: Ryan Scott Stability: Provisional Portability: Portable Exports functions which adjust code pages on Windows, and do nothing on other operating systems. -} module System.IO.CodePage ( -- * Adjusting 'CodePage's withCP65001 , withCP1200 , withCP1201 , withCP12000 , withCP12001 , withCP1252 , withCodePage , withCodePageOptions -- * Notable 'CodePage's , CodePage , cp65001 , cp1200 , cp1201 , cp12000 , cp12001 , cp1252 -- * 'Options' , Options , defaultOptions -- ** Record fields of 'Options' , chatty , nonWindowsBehavior -- ** 'NonWindowsBehavior' , NonWindowsBehavior -- ** Constructing 'NonWindowsBehavior' , nonWindowsDoNothing , nonWindowsFallbackCodePageEncoding , defaultFallbackCodePageEncoding ) where import Control.Exception (bracket_) import Control.Monad (when) import Data.Foldable (forM_) import GHC.IO.Encoding (textEncodingName) import System.IO ( TextEncoding, hGetEncoding, hPutStrLn, hSetEncoding , stderr, stdin, stdout ) import System.IO.CodePage.Internal #if MIN_VERSION_base(4,5,0) import GHC.IO.Encoding (getLocaleEncoding, setLocaleEncoding) #endif #ifdef WINDOWS import System.Win32.CodePage hiding (CodePage) #endif -- | Sets the code page for an action to UTF-8 as necessary. withCP65001 :: IO a -> IO a withCP65001 = withCodePage cp65001 -- | Sets the code page for an action to UTF-16LE as necessary. withCP1200 :: IO a -> IO a withCP1200 = withCodePage cp1200 -- | Sets the code page for an action to UTF-16BE as necessary. withCP1201 :: IO a -> IO a withCP1201 = withCodePage cp1201 -- | Sets the code page for an action to UTF-32LE as necessary. withCP12000 :: IO a -> IO a withCP12000 = withCodePage cp12000 -- | Sets the code page for an action to UTF-32BE as necessary. withCP12001 :: IO a -> IO a withCP12001 = withCodePage cp12001 -- | Sets the code page for an action to Latin1 as necessary. withCP1252 :: IO a -> IO a withCP1252 = withCodePage cp1252 -- | Sets the code page for an action as necessary. -- -- On operating systems besides Windows, this will make an effort to change -- the current 'TextEncoding' to something that is equivalent to the supplied -- 'CodePage'. Currently, the only supported 'CodePage's on non-Windows OSes -- are 'cp65001', 'cp1200', 'cp1201', 'cp12000', and 'cp12001'. Supplying any -- other 'CodePage' will result in a runtime error on non-Windows OSes. (If you -- would like to configure this behavior, use 'withCodePageOptions' instead.) withCodePage :: CodePage -> IO a -> IO a withCodePage = withCodePageOptions defaultOptions -- | Sets the code page for an action as necessary. If the 'Bool' argument is 'True', -- this function will emit a warning to @stderr@ indicating that the code page has -- been changed. ('withCodePage' sets this argument to 'False'.) -- Taken from the stack codebase -- (https://github.com/commercialhaskell/stack/blob/21e517ba88b3c6bee475fb00ad95f280e7285a54/src/main/Main.hs#L82-L123) -- which is under a 3-clause BSD license withCodePageOptions :: Options -> CodePage -> IO a -> IO a withCodePageOptions (Options{chatty, nonWindowsBehavior}) cp inner = case nonWindowsBehavior of NonWindowsDoNothing -> inner NonWindowsFallbackCodePageEncoding fallback -> do #ifdef WINDOWS origCPI <- getConsoleCP origCPO <- getConsoleOutputCP #else -- These are never used on non-Windows OSes, -- so their values are irrelevant let origCPI = 0 origCPO = 0 #endif mbOrigStdinEnc <- hGetEncoding stdin mbOrigStdoutEnc <- hGetEncoding stdout mbOrigStderrEnc <- hGetEncoding stderr #if MIN_VERSION_base(4,5,0) origLocaleEnc <- getLocaleEncoding #endif let expected = codePageEncoding' fallback cp expectedName = textEncodingName expected warn typ = when chatty $ hPutStrLn stderr $ concat [ "Setting" , typ , " codepage to " ++ show cp , if expectedName == ("CP" ++ show cp) then "" else " (" ++ expectedName ++ ")" ] #ifdef WINDOWS setInput = origCPI /= cp setOutput = origCPO /= cp #else -- Crude, but the best available option setInput = fmap textEncodingName mbOrigStdinEnc /= Just expectedName setOutput = fmap textEncodingName mbOrigStdoutEnc /= Just expectedName #endif #if MIN_VERSION_base(4,5,0) setLocale = textEncodingName origLocaleEnc /= expectedName #endif fixInput | setInput = bracket_ (do setConsoleCP' cp hSetEncoding stdin expected ) (do setConsoleCP' origCPI forM_ mbOrigStdinEnc $ hSetEncoding stdin ) | otherwise = id fixOutput | setOutput = bracket_ (do setConsoleOutputCP' cp hSetEncoding stdout expected hSetEncoding stderr expected ) (do setConsoleOutputCP' origCPO forM_ mbOrigStdoutEnc $ hSetEncoding stdout forM_ mbOrigStderrEnc $ hSetEncoding stderr ) | otherwise = id fixLocale #if MIN_VERSION_base(4,5,0) | setLocale = bracket_ (do when chatty $ hPutStrLn stderr $ unwords [ "Setting locale encoding to" , expectedName ] setLocaleEncoding expected) (setLocaleEncoding origLocaleEnc) | otherwise #endif = id case (setInput, setOutput) of (False, False) -> return () (True, True) -> warn "" (True, False) -> warn " input" (False, True) -> warn " output" fixInput $ fixOutput $ fixLocale inner codePageEncoding' :: (CodePage -> TextEncoding) -> CodePage -> TextEncoding #ifdef WINDOWS codePageEncoding' _ = codePageEncoding #else codePageEncoding' = id #endif setConsoleCP', setConsoleOutputCP' :: CodePage -> IO () #ifdef WINDOWS setConsoleCP' = setConsoleCP setConsoleOutputCP' = setConsoleOutputCP #else setConsoleCP' _ = return () setConsoleOutputCP' _ = return () #endif code-page-0.2.1/src/System/IO/CodePage/0000755000000000000000000000000007346545000015560 5ustar0000000000000000code-page-0.2.1/src/System/IO/CodePage/Internal.hs0000644000000000000000000000641007346545000017671 0ustar0000000000000000{-# LANGUAGE CPP #-} {-| Module: System.IO.CodePage.Internal Copyright: (C) 2018 Ryan Scott License: BSD-style (see the file LICENSE) Maintainer: Ryan Scott Stability: Experimental Portability: Portable Various internals used by "System.IO.CodePage". Note that this is an internal module, and as such, the API presented here is not guaranteed to be stable, even between minor releases of this library. -} module System.IO.CodePage.Internal where import System.IO (TextEncoding, latin1, utf8, utf16le, utf16be, utf32le, utf32be) #ifdef WINDOWS import qualified System.Win32.CodePage as Win32 (CodePage) #else import Data.Word (Word32) #endif -- | A numeric type representing Windows code pages. type CodePage = #ifdef WINDOWS Win32.CodePage #else Word32 #endif -- | The UTF-8 code page. cp65001 :: CodePage cp65001 = 65001 -- | The UTF-16LE code page. cp1200 :: CodePage cp1200 = 1200 -- | The UTF-16BE code page. cp1201 :: CodePage cp1201 = 1201 -- | The UTF-32LE code page. cp12000 :: CodePage cp12000 = 12000 -- | The UTF-32BE code page. cp12001 :: CodePage cp12001 = 12001 -- | The Latin1 code page. cp1252 :: CodePage cp1252 = 1252 -- | Options that specify how 'withCodePage' and friends should work. data Options = Options { chatty :: Bool -- ^ If 'True', emit a warning to @stderr@ indicating that the code page has -- been changed. If 'False', don't emit any warnings. , nonWindowsBehavior :: NonWindowsBehavior -- ^ Configures how 'withCodePage' and friends should work on non-Windows -- operating systems. } -- | The default 'Options': -- -- @ -- 'Options' -- { 'chatty' = 'False' -- , 'nonWindowsBehavior' = -- 'nonWindowsFallbackCodePageEncoding' 'defaultFallbackCodePageEncoding' -- } -- @ defaultOptions :: Options defaultOptions = Options { chatty = False , nonWindowsBehavior = nonWindowsFallbackCodePageEncoding defaultFallbackCodePageEncoding } -- | Specifies how 'withCodePage' and friends should work on operating systems -- other than Windows. data NonWindowsBehavior = NonWindowsDoNothing -- ^ Don't do anything at all on non-Windows OSes. | NonWindowsFallbackCodePageEncoding (CodePage -> TextEncoding) -- ^ On non-Windows OSes, change the 'TextEncoding' by converting the -- 'CodePage' argument to a 'TextEncoding' using the supplied function. -- | Don't do anything at all on non-Windows OSes. nonWindowsDoNothing :: NonWindowsBehavior nonWindowsDoNothing = NonWindowsDoNothing -- | On non-Windows OSes, change the 'TextEncoding' by converting the -- 'CodePage' argument to a 'TextEncoding' using the supplied function. nonWindowsFallbackCodePageEncoding :: (CodePage -> TextEncoding) -> NonWindowsBehavior nonWindowsFallbackCodePageEncoding = NonWindowsFallbackCodePageEncoding -- | Provides a best-effort attempt to convert a 'CodePage' to a 'TextEncoding' -- on non-Windows OSes. Errors if given a 'CodePage' that it doesn't know how -- to convert. defaultFallbackCodePageEncoding :: CodePage -> TextEncoding defaultFallbackCodePageEncoding cp | cp == cp65001 = utf8 | cp == cp1200 = utf16le | cp == cp1201 = utf16be | cp == cp12000 = utf32le | cp == cp12001 = utf32be | cp == cp1252 = latin1 | otherwise = error $ "Don't know fallback text encoding for CP" ++ show cp code-page-0.2.1/src/System/Win32/0000755000000000000000000000000007346545000014504 5ustar0000000000000000code-page-0.2.1/src/System/Win32/CodePage.hsc0000644000000000000000000000451407346545000016656 0ustar0000000000000000{-# LANGUAGE CPP #-} {-# LANGUAGE ForeignFunctionInterface #-} {-| Module: System.Win32.CodePage Copyright: (C) 2016-2017 Ryan Scott License: BSD-style (see the file LICENSE) Maintainer: Ryan Scott Stability: Provisional Portability: Portable On Windows, this exports functions for getting, setting, and analyzing code pages. On other operating systems, this exports nothing. -} module System.Win32.CodePage ( #ifdef WINDOWS -- * The 'CodePage' type CodePage -- * Getting and setting code pages , getConsoleCP , getConsoleOutputCP , setConsoleCP , setConsoleOutputCP , getACP , getOEMCP -- * Code page encodings , codePageEncoding , mkCodePageEncoding -- * Valid code pages , isValidCodePage , installedCodePages , supportedCodePages -- * 'CodePage'-aware Unicode conversion , stringToUnicode #endif ) where #ifdef WINDOWS import Data.IORef import Data.List import Foreign.C.String import Foreign.Ptr import GHC.IO.Encoding.CodePage (codePageEncoding, mkCodePageEncoding) import System.Win32.Console import System.Win32.NLS import System.Win32.Types # include ## include "windows_cconv.h" type CODEPROC_ENUMW = LPWSTR -> IO BOOL foreign import WINDOWS_CCONV "windows.h EnumSystemCodePagesW" c_EnumSystemCodePagesW :: FunPtr CODEPROC_ENUMW -> DWORD -> IO BOOL str_EnumSystemCodePagesW :: String str_EnumSystemCodePagesW = "EnumSystemCodePagesW" foreign import WINDOWS_CCONV "wrapper" mkCodeProcEnumW :: CODEPROC_ENUMW -> IO (FunPtr CODEPROC_ENUMW) cP_INSTALLED, cP_SUPPORTED :: DWORD cP_INSTALLED = #{const CP_INSTALLED} cP_SUPPORTED = #{const CP_SUPPORTED} -- | Enumerates all installed code pages in sorted order. installedCodePages :: IO [CodePage] installedCodePages = systemCodePages cP_INSTALLED -- | Enumerates all supported code pages in sorted order. supportedCodePages :: IO [CodePage] supportedCodePages = systemCodePages cP_SUPPORTED systemCodePages :: DWORD -> IO [CodePage] systemCodePages flags = do cpRef <- newIORef [] fptr <- mkCodeProcEnumW $ \cpLPWStr -> do cpStr <- peekCWString cpLPWStr modifyIORef cpRef (read cpStr :) return True failIfFalse_ str_EnumSystemCodePagesW $ c_EnumSystemCodePagesW fptr flags freeHaskellFunPtr fptr modifyIORef cpRef sort readIORef cpRef #endif code-page-0.2.1/tests/0000755000000000000000000000000007346545000012671 5ustar0000000000000000code-page-0.2.1/tests/Tests.hs0000644000000000000000000000104007346545000014322 0ustar0000000000000000{-| Module: Tests Copyright: (C) 2016-2017 Ryan Scott License: BSD-style (see the file LICENSE) Maintainer: Ryan Scott Stability: Provisional Portability: Portable Ensures that functions from "System.IO.CodePage" work properly. -} module Main (main) where import System.IO.CodePage printUnicodeStrings :: IO () printUnicodeStrings = do putStrLn "κόσμε" putStrLn "→" putStrLn "☀☁☂☃☄" main :: IO () main = withCP1252 $ withCodePageOptions defaultOptions{chatty = True} cp65001 printUnicodeStrings