ls-usb-0.1.0.13: ls-usb.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE PackageImports #-}
{-# LANGUAGE UnicodeSyntax #-}
{-|
Module : Main
Copyright : 2009–2012 Roel van Dijk
License : BSD3 (see the file LICENSE)
Maintainer : Roel van Dijk <vandijk.roel@gmail.com>
-}
module Main where
--------------------------------------------------------------------------------
-- Imports
--------------------------------------------------------------------------------
import "ansi-wl-pprint" Text.PrettyPrint.ANSI.Leijen ( putDoc, plain )
import "base" Control.Monad ( (=<<) )
import "base" Data.Bool ( Bool(False, True), otherwise )
import "base" Data.Data ( Data )
import "base" Data.Function ( ($), const, id )
import "base" Data.Functor ( (<$>), fmap )
import "base" Data.Int ( Int )
import "base" Data.List ( (++), foldr, map )
import "base" Data.Typeable ( Typeable )
import "base" Data.Word ( Word8 )
import "base" Data.Version ( showVersion )
import "base" Prelude ( fromIntegral )
import "base" System.IO ( IO, putStrLn )
import "base" Text.Show ( Show )
#if __GLASGOW_HASKELL__ < 700
import "base" Control.Monad ( (>>=), (>>), fail )
#endif
import "base-unicode-symbols" Data.Function.Unicode ( (∘) )
import "base-unicode-symbols" Data.Bool.Unicode ( (∧), (∨) )
import "base-unicode-symbols" Data.Eq.Unicode ( (≡) )
import "cmdargs" System.Console.CmdArgs.Implicit
( (&=)
, cmdArgs, def, details, explicit, help
, isLoud, name, summary, typ, verbosity
)
import "this" PrettyDevList ( DescribedDevice(..), ppDevices, brightStyle, darkStyle )
import "this" Paths_ls_usb ( version )
import "usb" System.USB.Initialization
( Verbosity(PrintNothing), newCtx, setDebug )
import "usb" System.USB.Enumeration
( getDevices, busNumber, deviceAddress )
import "usb" System.USB.Descriptors
( VendorId, ProductId, getDeviceDesc, deviceVendorId, deviceProductId )
import "usb-id-database" System.USB.IDDB.LinuxUsbIdRepo ( staticDb )
import qualified "vector" Data.Vector as V
--------------------------------------------------------------------------------
-- Main
--------------------------------------------------------------------------------
data Options = Options { vid ∷ [Int]
, pid ∷ [Int]
, bus ∷ [Int]
, address ∷ [Int]
, nocolour ∷ Bool
, darker ∷ Bool
} deriving (Show, Data, Typeable)
defaultOpts ∷ Options
defaultOpts = Options
{ vid = def &= explicit &= name "vid" &= typ "VID"
&= help "List devices with this VID"
, pid = def &= explicit &= name "pid" &= typ "PID"
&= help "List devices with this PID"
, bus = def &= explicit &= name "b" &= name "bus" &= typ "BUS"
&= help "List devices on this BUS"
, address = def &= explicit &= name "a" &= name "address" &= typ "ADDR"
&= help "List devices with this ADDRESS"
, nocolour = def &= explicit &= name "nc" &= name "nocolour" &= name "nocolor"
&= help "Don't colour the output"
, darker = def &= explicit &= name "dark"
&= help "Use darker colours (for bright backgrounds)"
} &= verbosity
&= help "Lists connected USB devices"
&= summary ("ls-usb " ++ showVersion version ++ ", (C) Roel van Dijk 2009-2012")
&= details ["Please ensure you have sufficient rights before running with higher verbosity"]
main ∷ IO ()
main = do opts ← cmdArgs defaultOpts
verbose ← isLoud
db ← staticDb
ctx ← newCtx
setDebug ctx PrintNothing
devs ← fmap (V.toList ∘ V.filter (filterFromOpts opts)) ∘
V.mapM (\dev -> DD dev <$> getDeviceDesc dev) =<<
getDevices ctx
let style | darker opts = darkStyle
| otherwise = brightStyle
(putDoc ∘ if nocolour opts then plain else id)
=<< ppDevices style db verbose devs
putStrLn ""
filterFromOpts ∷ Options → F DescribedDevice
filterFromOpts opts = andF $ map (filterNonEmpty ∘ ($ opts))
[ map (matchVID ∘ fromIntegral) ∘ vid
, map (matchPID ∘ fromIntegral) ∘ pid
, map (matchBus ∘ fromIntegral) ∘ bus
, map (matchDevAddr ∘ fromIntegral) ∘ address
]
--------------------------------------------------------------------------------
-- Filters
--------------------------------------------------------------------------------
type F α = α → Bool
-- Construct a filter combinator from a binary boolean operator.
binBoolOpToFComb ∷ (Bool → Bool → Bool) → F α → F α → F α
binBoolOpToFComb (⊗) f g = \x → f x ⊗ g x
(<∨>) ∷ F α → F α → F α
(<∨>) = binBoolOpToFComb (∨)
(<∧>) ∷ F α → F α → F α
(<∧>) = binBoolOpToFComb (∧)
andF ∷ [F α] → F α
andF = foldr (<∧>) (const True)
orF ∷ [F α] → F α
orF = foldr (<∨>) (const False)
filterNonEmpty ∷ [F α] → F α
filterNonEmpty [] = const True
filterNonEmpty xs = foldr (<∨>) (const False) xs
--------------------------------------------------------------------------------
-- Specific Device filters
--------------------------------------------------------------------------------
matchVID ∷ VendorId → F DescribedDevice
matchVID vid' = (vid' ≡) ∘ deviceVendorId ∘ deviceDesc
matchPID ∷ ProductId → F DescribedDevice
matchPID pid' = (pid' ≡) ∘ deviceProductId ∘ deviceDesc
matchBus ∷ Word8 → F DescribedDevice
matchBus bus' = (bus' ≡) ∘ busNumber ∘ device
matchDevAddr ∷ Word8 → F DescribedDevice
matchDevAddr addr = (addr ≡) ∘ deviceAddress ∘ device