Skip to content

Latest commit

 

History

History
923 lines (691 loc) · 21.7 KB

Libraries.org

File metadata and controls

923 lines (691 loc) · 21.7 KB

Libraries

Libraries

System Programming in Haskell

Directory

Get current Directory

> import System.Directory
> 
> getCurrentDirectory 
"/home/tux/PycharmProjects/Haskell"
> 

Change Current Directory

> import System.Directory
> 
> setCurrentDirectory "/"
> 
> getCurrentDirectory 
"/"
> 
getCurrentDirectory :: IO FilePath
> 
> 
> fmap (=="/") getCurrentDirectory 
True
> 
> liftM (=="/") getCurrentDirectory 
True
> 

List Directory Contents

> import System.Directory
>
>  getDirectoryContents "/usr"
[".","include","src","local","bin","games","share","sbin","lib",".."]
> 
> :t getDirectoryContents 
getDirectoryContents :: FilePath -> IO [FilePath]
> 

Special Directories Location

> getHomeDirectory
"/home/tux"
> 
> getAppUserDataDirectory "myApp"
"/home/tux/.myApp"
> 
> getUserDocumentsDirectory
"/home/tux"
> 

Running External Commands

> import System.Cmd
> 
> :t rawSystem
rawSystem :: String -> [String] -> IO GHC.IO.Exception.ExitCode
> 
> rawSystem "ls" ["-l", "/usr"]
total 260
drwxr-xr-x   2 root root 118784 Abr 26 03:38 bin
drwxr-xr-x   2 root root   4096 Abr 10  2014 games
drwxr-xr-x 131 root root  36864 Mar 11 01:38 include
drwxr-xr-x 261 root root  53248 Abr 14 16:46 lib
drwxr-xr-x  10 root root   4096 Dez  2 18:55 local
drwxr-xr-x   2 root root  12288 Abr  3 13:28 sbin
drwxr-xr-x 460 root root  20480 Abr 26 03:38 share
drwxr-xr-x  13 root root   4096 Jan 13 21:03 src
ExitSuccess
>

Reading input from a system command in Haskell

This command executes ls -la and gets the output.

import System.Process
test = readProcess "ls" ["-a"] ""


> import System.Process
> let test = readProcess "ls" ["-a"] ""
> 
> :t test
test :: IO String
> 
> test >>= putStrLn 
.
..
adt2.py
adt.py
build.sh
build_zeromq.sh
clean.sh
codes
comparison.ods
dict.sh
ffi
figure1.png
.git

Data.Time

System

Get current year / month / day in Haskell

UTC time:

Note that the UTC time might differ from your local time depending on the timezone.

import Data.Time.Clock
import Data.Time.Calendar

main = do
    now <- getCurrentTime
    let (year, month, day) = toGregorian $ utctDay now
    putStrLn $ "Year: " ++ show year
    putStrLn $ "Month: " ++ show month
    putStrLn $ "Day: " ++ show day

Get Current Time

Local time:

It is also possible to get your current local time using your system’s default timezone:

import Data.Time.Clock
import Data.Time.Calendar
import Data.Time.LocalTime

main = do
    now <- getCurrentTime
    timezone <- getCurrentTimeZone
    let zoneNow = utcToLocalTime timezone now
    let (year, month, day) = toGregorian $ localDay zoneNow
    putStrLn $ "Year: " ++ show year
    putStrLn $ "Month: " ++ show month
    putStrLn $ "Day: " ++ show day
import Data.Time.Clock
import Data.Time.LocalTime

main = do
    now <- getCurrentTime
    timezone <- getCurrentTimeZone
    let (TimeOfDay hour minute second) = localTimeOfDay $ utcToLocalTime timezone now
    putStrLn $ "Hour: " ++ show hour
    putStrLn $ "Minute: " ++ show minute
    -- Note: Second is of type @Pico@: It contains a fractional part.
    -- Use @fromIntegral@ to convert it to a plain integer.
    putStrLn $ "Second: " ++ show second

Documentation By Examples - GHCI shell

Date Time Manipulation

import Data.Time

> :t getCurrentTime
getCurrentTime :: IO UTCTime
> 


> t <- getCurrentTime
> t
2015-03-04 23:22:39.046752 UTC
> 

> :t t
t :: UTCTime


> today <- fmap utctDay getCurrentTime 
> today
2015-03-04
> :t today
today :: Day
> 
> 

>  let (year, _, _) = toGregorian today
> year
2015
> 

> :t fromGregorian 2015 0 0
fromGregorian 2015 0 0 :: Day

> fromGregorian 2015 0 0
2015-01-01
> 

> diffDays today (fromGregorian year 0 0)
62
> 

> import Text.Printf
>
> tm <- getCurrentTime
>  let (year, month, day) = toGregorian (utctDay tm)
> year
2015
> month
3
> day
4
> 

> printf "The current date is %04d %02d %02d\n" year month day
The current date is 2015 03 04


> import System.Locale
> 
> fmap (formatTime defaultTimeLocale "%Y-%m-%d") getCurrentTime
"2015-03-04"
> 
> 

Difference between two dates

> import Data.Time
> import Data.Time.Clock.POSIX
> 

> let bree = UTCTime (fromGregorian 1981 6 16) (timeOfDayToTime $ TimeOfDay 4 35 25) -- 1981-06-16 04:35:25 UTC
> bree
1981-06-16 04:35:25 UTC
> 


> let nat  = UTCTime (fromGregorian 1973 1 18) (timeOfDayToTime $ TimeOfDay 3 45 50) -- 1973-01-18 03:45:50 UTC
> nat
1973-01-18 03:45:50 UTC
> 


> 
> let bree' = read "1981-06-16 04:35:25" :: UTCTime
> bree'
1981-06-16 04:35:25 UTC
> :t bree'
bree' :: UTCTime
> 
> let nat'  = read "1973-01-18 03:45:50" :: UTCTime
> 
> nat'
1973-01-18 03:45:50 UTC
> 


> difference = diffUTCTime bree nat / posixDayLength
> difference 
3071.03443287037s
> 

>  "There were " ++ (show $ round difference) ++ " days between Nat and Bree"
"There were 3071 days between Nat and Bree"
> 

Day in a Week/Month/Year or Week Number

> import Data.Time
> import Data.Time.Calendar.MonthDay
> import Data.Time.Calendar.OrdinalDate
> import System.Locale

> :t fromGregorian
fromGregorian :: Integer -> Int -> Int -> Day

> let (year, month, day) = (1981, 6, 16) :: (Integer , Int , Int )
> 
> let date = (fromGregorian year month day)
> date
1981-06-16
> 
> let (week, week_day) = sundayStartWeek date
> week
24
> week_day
2
> 

> let (year_, year_day) = toOrdinalDate date
> year_
1981
> year_day
167
> 


> let (week_day_name, _) = wDays defaultTimeLocale !! week_day
> week_day_name
"Tuesday"
> 

> :t defaultTimeLocale 
defaultTimeLocale :: TimeLocale
> 
> defaultTimeLocale 
TimeLocale {wDays = [("Sunday","Sun"),("Monday","Mon"),("Tuesday","Tue"),("Wednesday","Wed"),("Thursday","Thu"),("Friday","Fri"),("Saturday","Sat")], months = [("January","Jan"),("February","Feb"),("March","Mar"),("April","Apr"),("May","May"),("June","Jun"),("July","Jul"),("August","Aug"),("September","Sep"),("October","Oct"),("November","Nov"),("December","Dec")], intervals = [("year","years"),("month","months"),("day","days"),("hour","hours"),("min","mins"),("sec","secs"),("usec","usecs")], amPm = ("AM","PM"), dateTimeFmt = "%a %b %e %H:%M:%S %Z %Y", dateFmt = "%m/%d/%y", timeFmt = "%H:%M:%S", time12Fmt = "%I:%M:%S %p"}
> 
> 

Parsing Dates and Times from Strings

> import Data.Time
> import Data.Time.Format
> import Data.Time.Clock.POSIX
> import System.Locale

> let day:: Day ; day = readTime defaultTimeLocale "%F" "1998-06-03"
> 
> day
1998-06-03
> 

Printing a Date

> import Data.Time
> import Data.Time.Format
> import System.Locale
> 
> now <- getCurrentTime
> :t now
now :: UTCTime
> 
> formatTime defaultTimeLocale "The date is %A (%a) %d/%m/%Y" now
"The date is Wednesday (Wed) 04/03/2015"
> 
> 

> let t = do now <- getCurrentTime ; return $ formatTime defaultTimeLocale "The date is %A (%a) %d/%m/%Y" now
> t
"The date is Wednesday (Wed) 04/03/2015"
> 

Credits:

Bytestring

Overview

Bytestring is a built in library for fast and efficient string and binary data processing. ByteStrings are not designed for Unicode. For Unicode strings the Text type must be used from the text package.

There are two flavours of bytestring, the lazy and strict.

  • Strict Bytestring: Data.ByteString

String as a single large array, suitable for passing data between C and Haskell.

  • Lazy Bytestring: Data.ByteString.Lazy

Lazy list of strict chunks which makes it suitable for I/O streaming tasks

Import Bytestring

To avoid name conflicts the modules must be imported as qualified.

import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BC

import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BLC

Example

    > import qualified Data.ByteString as B
    > import qualified Data.ByteString.Char8 as BC
    > 
    > import qualified Data.ByteString.Lazy as BL
    > import qualified Data.ByteString.Lazy.Char8 as BLC
    > 
    > let (|>) x f = f x
    > 


{- String to Bytestring -}
{---------------------------------------------}

    > BC.pack "hello world" 
    "hello world"

    > BC.pack "čušpajž日本語"
    "\ruapaj~\229,\158"
    > 
    > :t BC.pack "čušpajž日本語"
    BC.pack "čušpajž日本語" :: B.ByteString
    > 

{- Strict to Lazy Conversion -}
{---------------------------------------------}

    > let s_strict = BC.pack  "čušpajž日本語"
    > s_strict 
    "\ruapaj~\229,\158"
    > 

    > let s_lazy = BLC.pack  "čušpajž日本語" 
    > s_lazy 
    "\ruapaj~\229,\158"
    > 
    > :t s_
    s_lazy    s_strict
    > :t s_lazy 
    s_lazy :: BL.ByteString
    > 

    {- Strict to Lazy -}
       
    > :t BL.fromChunks
    BL.fromChunks :: [B.ByteString] -> BL.ByteString
    > 

    > let new_lazy = BL.fromChunks [s_strict]
    > new_lazy 
    "\ruapaj~\229,\158"
    > :t new_lazy
    new_lazy :: BL.ByteString
    > 


{- Lazy to Strict -}
{---------------------------------------------}

    > let new_strict = B.concat $ BL.toChunks s_lazy 
    > new_strict 
    "\ruapaj~\229,\158"
    > :t new_strict
    new_strict :: B.ByteString
    > 

    > BC.putStrLn new_strict 
    uapaj~�,
    > 

    > BLC.putStrLn new_lazy 
    uapaj~�,
    > 


{- Serialization -}
{---------------------------------------------}

    > import qualified Data.Binary as D
    > {- Serializes Haskell Data to Lazy Bytestring -}
    > 

    > :t D.encode
    D.encode :: D.Binary a => a -> BL.ByteString
    > 

    > :t D.decode
    D.decode :: D.Binary a => BL.ByteString -> a
    >


    > let a = D.encode 10 
    > a
    "\NUL\NUL\NUL\NUL\n"
    > :t a
    a :: BL.ByteString
    > 
    > D.decode a
    ()
    > D.decode a :: Int
    *** Exception: Data.Binary.Get.runGet at position 0: demandInput: not enough bytes
    > D.decode a :: Integer
    10
    > 



    > let b = D.encode (Just 10 :: Maybe Int)
    > :t b
    b :: BL.ByteString
    > b
    "\SOH\NUL\NUL\NUL\NUL\NUL\NUL\NUL\n"
    > 

    > D.decode b :: Maybe Int
    Just 10
    >

    > let c = D.encode (Nothing :: Maybe Int)
    > c
    "\NUL"
    >
    > D.decode c :: Maybe Int
    Nothing
    >


    > let d = D.encode (3.11415e4 :: Double)
    > d
    "\SOH\SOH\NUL\NUL\NUL\NUL\NUL\NUL\NUL\a\NUL\NUL\NUL\NUL`i\RS\255\255\255\255\255\255\255\218"
    > 

{- Bytes to Bytestring -}
{---------------------------------------------}

    {- Bytes are encoded as Word8 -}

    > :t B.pack
    B.pack :: [GHC.Word.Word8] -> B.ByteString
    > :t B.unpack
    B.unpack :: B.ByteString -> [GHC.Word.Word8]
    > 
    > :t BL.pack
    BL.pack :: [GHC.Word.Word8] -> BL.ByteString
    > :t BL.unpack
    BL.unpack :: BL.ByteString -> [GHC.Word.Word8]
    > 

    > let msg = B.pack [72,101,108,108,111,32,119,111,114,108,100]
    > msg
    "Hello world"

    > let bytes = B.unpack msg
    > bytes
    [72,101,108,108,111,32,119,111,114,108,100]
    > 

    > :t msg
    msg :: B.ByteString

    > :t bytes
    bytes :: [GHC.Word.Word8]
    > 

    {- Word8 to Int -}

    > :t fromIntegral 
    fromIntegral :: (Num b, Integral a) => a -> b
    > 

    > let x = 100 :: GHC.Word.Word8
    > x
    100
    > :t x
    x :: GHC.Word.Word8
    > 

    > let y = fromIntegral x :: Int
    > y
    100
    > :t y
    y :: Int
    > 

    > fromIntegral ( 100 :: GHC.Word.Word8) :: Int
    100
    > 

    > let bytes_int = map (\x -> fromIntegral x :: Int) bytes
    > bytes_int 
    [72,101,108,108,111,32,119,111,114,108,100]
    > :t bytes_int 
    bytes_int :: [Int]
    > 

    > let bytes_word8 = map (\x -> fromIntegral x ::  GHC.Word.Word8) bytes_int 
    > bytes_word8 
    [72,101,108,108,111,32,119,111,114,108,100]
    > :t bytes_word8 
    bytes_word8 :: [GHC.Word.Word8]
    > 

{- Bytes in Hexadecimal and Binary Format -}

    > import Numeric (showHex, showIntAtBase)
    > import Data.Char (intToDigit)
    > import Data.Bits (shiftL, shiftR, (.&.), (.|.))
    > import Data.Word (Word8)

    > 
        {- Bytes in Hexadecimal Format Low Endian -}
    > map (\n -> showHex n "") bytes
    ["48","65","6c","6c","6f","20","77","6f","72","6c","64"]
    > 
    > 

    {- Bytes in Hexadecimal Format Big Endian -}

    > reverse $ map (\n -> showHex n "") bytes
    ["64","6c","72","6f","77","20","6f","6c","6c","65","48"]
    > 

    {- Hexadecimal String Low Endian -}

    > concat $ map (\n -> showHex n "") bytes
    "48656c6c6f20776f726c64"
    > 

    {- Hexadecimal String Bing Ending -}
    > concat $ reverse $ map (\n -> showHex n "") bytes
    "646c726f77206f6c6c6548"
    > 

    {- Hexadecimal number to bytes -}

    
    > 
    > let num2hex = \n -> showHex n ""
    > 
    > let x = 0x646c726f77206f6c6c6548
    > x
    121404708502361365413651784
    > 
    > num2hex x
    "646c726f77206f6c6c6548"
    > 
    
    {- Split Bytes -}
    {-------------------------------------------}
    
    > iterate (\x -> shiftR x 8) 0x646c726f77206f6c6c6548 |> takeWhile ((/=) 0) |> map (.&. 0xFF)
    [72,101,108,108,111,32,119,111,114,108,100]
    > 
    >  map num2hex .  map (.&. 0xFF) . takeWhile ((/=) 0) .  iterate (\x -> shiftR x 8) $  0x646c726f77206f6c6c6548
    ["48","65","6c","6c","6f","20","77","6f","72","6c","64"]
    >

    > iterate (\x -> shiftR x 8) 0x646c726f77206f6c6c6548 |> takeWhile ((/=) 0) |> map (.&. 0xFF) |> map num2hex
    ["48","65","6c","6c","6f","20","77","6f","72","6c","64"]
    > 

    > iterate (\x -> shiftR x 8) 0x646c726f77206f6c6c6548 |> takeWhile ((/=) 0) |> map (.&. 0xFF) |> map num2hex |> concat
    "48656c6c6f20776f726c64"
    > 
    > iterate (\x -> shiftR x 8) 0x646c726f77206f6c6c6548 |> takeWhile ((/=) 0) |> map (.&. 0xFF) |> map num2hex |> reverse |> concat
    "646c726f77206f6c6c6548"
    > 

    > let int2word8 = \x -> fromIntegral x :: Word8
    > 
    > let num2bytes = map int2word8 . map (.&. 0xFF) . takeWhile ((/=) 0) .  iterate (\x -> shiftR x 8)

    > :t num2bytes
    num2bytes :: (Data.Bits.Bits a, Integral a) => a -> [Word8]
    > 
    > 
    > num2bytes 0x646c726f77206f6c6c6548
    [72,101,108,108,111,32,119,111,114,108,100]
    > 
    > num2bytes 0x646c726f77206f6c6c6548 |> map num2hex
    ["48","65","6c","6c","6f","20","77","6f","72","6c","64"]
    > 

    > num2bytes 0x646c726f77206f6c6c6548 |> BL.pack 
    "Hello world"
    > 
    > 
    
    {- Bytes to Int -}
    
    > let bytes = [72,101,108,108,111,32,119,111,114,108,100]
    > foldr (\b0 b1 -> (shiftL b1 8) + b0) 0 bytes
    121404708502361365413651784

    > num2hex . foldr (\b0 b1 -> (shiftL b1 8) + b0) 0 $ bytes 
    "646c726f77206f6c6c6548"
    > 

    > let bytes2int =  foldr (\b0 b1 -> (shiftL b1 8) + b0) 0
    > bytes2int bytes
    121404708502361365413651784
    > 

See also

Base64 Algorithm

Documentation in Hackage

ByteString

An efficient compact, immutable byte string type (both strict and lazy) suitable for binary or 8-bit character data.

The ByteString type represents sequences of bytes or 8-bit characters. It is suitable for high performance use, both in terms of large data quantities, or high speed requirements. The ByteString functions follow the same style as Haskell’s ordinary lists, so it is easy to convert code from using String to ByteString.

Data.Word

Unsigned integer types: Word8, Word16, Word32, Word64

Data.Word

Data.Binary package

Binary serialisation of Haskell values to and from lazy ByteStrings. The Binary library provides methods for encoding Haskell values as streams of bytes directly in memory. The resulting ByteString can then be written to disk, sent over the network, or futher processed (for example, compressed with gzip).

Data.Bits package

This module defines bitwise operations for signed and unsigned integers. Instances of the class Bits for the Int and Integer types are available from this module, and instances for explicitly sized integral types are available from the Data.Int and Data.Word modules.

Numeric

Odds and ends, mostly functions for reading and showing RealFloat-like kind of values.

Numeric

Data.Char

The Char type and associated operations.

Data.Char

Parse Binary Files

To decode a binary file it is necessary to know:

  • The Binary file format or specification
  • File Signature that comes in the file header.
  • Data Size (8 bits signed, 8 bits unsigned, ....)
  • Byte Endianess or Byte order (Little Endian or Big Endian)

This section will show how to parse the windows executable, PE32 executable.

PE32 Layout Specification

import Data.Word --- Unsigned integer types: Word8, Word16, Word32, Word64 

import Data.ByteString.Lazy as BL
import Data.ByteString.Char8 as BC
import Data.Binary
import Data.Binary.Get

> let (|>) x f = f x
> 

> :t BL.readFile 
BL.readFile :: FilePath -> IO BL.ByteString

> fdata <- BL.readFile "notepad.exe" 
> 
> :t fdata
fdata :: BL.ByteString
> 

> :t BL.take 
BL.take :: GHC.Int.Int64 -> BL.ByteString -> BL.ByteString


{- Read File Signare 2 bytes, always 0x5A4D OR ("MZ")
 - 
 -}
> BL.take 2 fdata
"MZ"
> 

> let toHex :: [Word8] -> [String] ;toHex = Prelude.map ( (\n -> showHex n "") . (\x -> fromIntegral x :: Int) )
> 
>  BL.take 2 fdata |> BL.unpack |> toHex 
["4d","5a"]
> 

read_dosHeader = do
  

PE32 Documentation

file:https://commons.wikimedia.org/wiki/File:RevEngPEFile.JPG

Dos Header Structure

From:

typedef struct _IMAGE_DOS_HEADER {      // DOS .EXE header
    WORD   e_magic;                     // Magic number
    WORD   e_cblp;                      // Bytes on last page of file
    WORD   e_cp;                        // Pages in file
    WORD   e_crlc;                      // Relocations
    WORD   e_cparhdr;                   // Size of header in paragraphs
    WORD   e_minalloc;                  // Minimum extra paragraphs needed
    WORD   e_maxalloc;                  // Maximum extra paragraphs needed
    WORD   e_ss;                        // Initial (relative) SS value
    WORD   e_sp;                        // Initial SP value
    WORD   e_csum;                      // Checksum
    WORD   e_ip;                        // Initial IP value
    WORD   e_cs;                        // Initial (relative) CS value
    WORD   e_lfarlc;                    // File address of relocation table
    WORD   e_ovno;                      // Overlay number
    WORD   e_res[4];                    // Reserved words
    WORD   e_oemid;                     // OEM identifier (for e_oeminfo)
    WORD   e_oeminfo;                   // OEM information; e_oemid specific
    WORD   e_res2[10];                  // Reserved words
    LONG   e_lfanew;                    // File address of new exe header
  } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

COFF Header

struct COFFHeader
{
   short Machine;
   short NumberOfSections;
   long TimeDateStamp;
   long PointerToSymbolTable;
   long NumberOfSymbols;
   short SizeOfOptionalHeader;
   short Characteristics;
}

GnuPlot

Installation:

$ cabal install gnuplot
$ sudo apt-get install gnuplot-x11 # Ubuntu/ Debian

Examples:

> import Graphics.Gnuplot.Simple
> plotList [] [(1, 1), (2, 2), (3, 3)]
> import Graphics.Gnuplot.Simple
> plotFunc [] (linearScale 1000 (-20,20)) (\x -> sin x / x)
> plotList [Title "A title", XLabel "x label"] [(2,10),(3,15),(4,14),(5,19)]
> plotList [Title "A title", XLabel "x label", YLabel "the y label"] [(2,10),(3,15),(4,14),(5,19)]

Doucumentation

This is a wrapper to gnuplot which lets you create 2D and 3D plots. Start a simple session with make ghci. This loads the module Graphics.Gnuplot.Simple which is ready for use in GHCi. It does not address all fancy gnuplot features in order to stay simple. For more sophisticated plots, especially batch generated graphics, I recommend Graphics.Gnuplot.Advanced. This module contains also an overview of the hierarchy of objects.

Graphics.Gnuplot