diff --git a/System/Terminfo.hs b/System/Terminfo.hs
deleted file mode 100644
--- a/System/Terminfo.hs
+++ /dev/null
@@ -1,162 +0,0 @@
--- |
--- Module      :  System.Terminfo
--- Copyright   :  (c) Bryan Richter (2013)
--- License     :  BSD-style
--- Maintainer  :  bryan.richter@gmail.com
---
--- This is a pure-Haskell (no FFI) module for accessing terminfo databases,
--- which contain characteristics, or capabilities, for the various
--- terminals such as screen, vt100, or xterm. Among other things, the
--- capabilities include the idiosyncratic character sequences needed to
--- send commands to the terminal. These commands include things like cursor
--- movement.
---
--- For a deeper understanding of terminfo, consult the man pages for
--- term(5) and terminfo(5).
---
--- There are three parts to this module: acquiring a terminfo database,
--- querying the database, and defining the capabilities.
---
--- This module is dead simple, so a single example will hopefully suffice
--- to demonstrate its usage.
---
--- @
--- import System.Terminfo
--- import System.Terminfo.Caps as C
--- uglyExample :: IO (Maybe Int)
--- uglyExample = do
---     term \<- fromJust \<$> lookupEnv \"TERM\"
---     db \<- 'acquireDatabase' term
---     let maxColors (Right d) = 'queryNumTermCap' d C.'MaxColors'
---     return $ maxColors db
--- @
---
--- >>> uglyExample
--- Just 256
---
-
-module System.Terminfo (
-    -- * Acquiring a Database
-      acquireDatabase
-    -- * Querying Capabilities
-    -- $queryFuncs
-    , queryBoolTermCap
-    , queryNumTermCap
-    , queryStrTermCap
-    -- * The Capabilities
-    -- $capabilities
-
-    -- * The Database Type
-    , TIDatabase
-
-    ) where
-
-import Control.Applicative ((<$>), (<|>))
-import Control.Error
-import Control.Monad ((<=<), filterM)
-import qualified Data.ByteString as B
-import qualified Data.Map.Lazy as M
-import System.Directory
-import System.FilePath
-import System.IO
-
-import System.Terminfo.Types
-import System.Terminfo.DBParse
-import System.Terminfo.Internal (terminfoDBLocs)
-import System.Terminfo.Caps
-
-data DBType = BerkeleyDB | DirTreeDB
-    deriving(Show)
-
--- Old MacDonald had a farm...
-type EIO = EitherT String IO
-
-acquireDatabase
-    :: String -- ^ System name
-    -> IO (Either String TIDatabase)
-       -- ^ A database object for the terminal, if it exists.
-acquireDatabase = runEitherT . (parseDBFile <=< findDBFile)
-
-findDBFile :: String -> EIO (DBType, FilePath)
-findDBFile term = case term of
-    (c:_) -> dbFileM c term `orLeft` "No terminfo db found"
-    _     -> hoistEither $ Left "User specified null terminal name"
-  where
-    orLeft = flip noteT
-    dbFileM c t = dirTreeDB c t <|> berkeleyDB
-
--- | Not implemented
-berkeleyDB :: MaybeT IO (DBType, FilePath)
-berkeleyDB = nothing
-
-dirTreeDB :: Char -> String -> MaybeT IO (DBType, FilePath)
-dirTreeDB c term = MaybeT $ do
-    path <- findFirst =<< map (</> [c] </> term) <$> terminfoDBLocs
-    return $ (,) DirTreeDB <$> path
-
-findFirst :: [FilePath] -> IO (Maybe FilePath)
-findFirst = fmap headMay . filterM doesFileExist
-
-parseDBFile :: (DBType, FilePath) -> EIO TIDatabase
-parseDBFile (db, f) = case db of
-    DirTreeDB -> extractDirTreeDB f
-    BerkeleyDB -> hoistEither
-        $ Left "BerkeleyDB support not yet implemented"
-
--- | Extract a 'TIDatabase' from the specified file. IO exceptions are
--- left to their own devices.
-extractDirTreeDB :: FilePath
-                 -> EIO TIDatabase
-extractDirTreeDB =
-    hoistEither . parseDB
-    <=< rightT . B.hGetContents
-    <=< rightT . flip openBinaryFile ReadMode
-  where
-    rightT = EitherT . fmap Right
-
-queryBoolTermCap :: TIDatabase
-                 -> BoolTermCap
-                 -> Bool
-queryBoolTermCap (TIDatabase (TCBMap vals) _ _) cap =
-    fromMaybe False $ M.lookup cap vals
-
-queryNumTermCap :: TIDatabase
-                -> NumTermCap
-                -> Maybe Int
-queryNumTermCap (TIDatabase _ (TCNMap vals) _) cap = M.lookup cap vals
-
--- | As this is a dead simple module, no \'smart\' handling of the
--- returned string is implemented. In particular, placeholders for
--- buffer characters and command arguments are left as-is. This will be
--- rectified eventually, probably in a separate module.
-queryStrTermCap :: TIDatabase
-                -> StrTermCap
-                -> Maybe String
-queryStrTermCap (TIDatabase _ _ (TCSMap vals)) cap = M.lookup cap vals
-
---
--- DOCUMENTATION
---
-
-
-
--- $queryFuncs
---
--- For each of these three actions, the first argument is the database to
--- query, and the second argument is the capability to look up.
---
--- I'm not super proud of this interface, but it's the best I can manage at
--- present without requiring lots of mostly-empty case expressions. Perhaps
--- someone will suggest a more interesting solution.
-
--- $capabilities
---
--- /see/ "System.Terminfo.Caps"
---
--- There are no less than 497 capabilities specified in term.h on my
--- Intel-based Ubuntu 12.04 notebook (slightly fewer in the terminfo(5) man
--- page). The naive way of making these available to the user is as data
--- constructors, and that is what I have done here.
---
--- The number of constructors absolutely crushes the namespace. I have
--- sequestered them into their own module to try to alleviate the pain.
diff --git a/System/Terminfo/Caps.hs b/System/Terminfo/Caps.hs
deleted file mode 100644
--- a/System/Terminfo/Caps.hs
+++ /dev/null
@@ -1,519 +0,0 @@
--- | There is an egregious number of capabilities. They are sequestered in
--- this module to preserve namespace sanity.
---
--- For descriptions of these, consult terminfo(5).
-
-module System.Terminfo.Caps (
-    -- * Boolean
-      BoolTermCap(..)
-    -- * Numeric
-    , NumTermCap(..)
-    -- * String
-    , StrTermCap(..)
-    ) where
-
-data BoolTermCap
-    = AutoLeftMargin
-    | AutoRightMargin
-    | NoEscCtlc
-    | CeolStandoutGlitch
-    | EatNewlineGlitch
-    | EraseOverstrike
-    | GenericType
-    | HardCopy
-    | HasMetaKey
-    | HasStatusLine
-    | InsertNullGlitch
-    | MemoryAbove
-    | MemoryBelow
-    | MoveInsertMode
-    | MoveStandoutMode
-    | OverStrike
-    | StatusLineEscOk
-    | DestTabsMagicSmso
-    | TildeGlitch
-    | TransparentUnderline
-    | XonXoff
-    | NeedsXonXoff
-    | PrtrSilent
-    | HardCursor
-    | NonRevRmcup
-    | NoPadChar
-    | NonDestScrollRegion
-    | CanChange
-    | BackColorErase
-    | HueLightnessSaturation
-    | ColAddrGlitch
-    | CrCancelsMicroMode
-    | HasPrintWheel
-    | RowAddrGlitch
-    | SemiAutoRightMargin
-    | CpiChangesRes
-    | LpiChangesRes
-    | BackspacesWithBs
-    | CrtNoScrolling
-    | NoCorrectlyWorkingCr
-    | GnuHasMetaKey
-    | LinefeedIsNewline
-    | HasHardwareTabs
-    | ReturnDoesClrEol
-    deriving (Ord, Eq, Enum, Bounded, Show)
-
-data NumTermCap
-    = Columns
-    | InitTabs
-    | Lines
-    | LinesOfMemory
-    | MagicCookieGlitch
-    | PaddingBaudRate
-    | VirtualTerminal
-    | WidthStatusLine
-    | NumLabels
-    | LabelHeight
-    | LabelWidth
-    | MaxAttributes
-    | MaximumWindows
-    | MaxColors
-    | MaxPairs
-    | NoColorVideo
-    | BufferCapacity
-    | DotVertSpacing
-    | DotHorzSpacing
-    | MaxMicroAddress
-    | MaxMicroJump
-    | MicroColSize
-    | MicroLineSize
-    | NumberOfPins
-    | OutputResChar
-    | OutputResLine
-    | OutputResHorzInch
-    | OutputResVertInch
-    | PrintRate
-    | WideCharSize
-    | Buttons
-    | BitImageEntwining
-    | BitImageType
-    | MagicCookieGlitchUl
-    | CarriageReturnDelay
-    | NewLineDelay
-    | BackspaceDelay
-    | HorizontalTabDelay
-    | NumberOfFunctionKeys
-    deriving (Ord, Eq, Enum, Bounded, Show)
-
-data StrTermCap
-    = BackTab
-    | Bell
-    | CarriageReturn
-    | ChangeScrollRegion
-    | ClearAllTabs
-    | ClearScreen
-    | ClrEol
-    | ClrEos
-    | ColumnAddress
-    | CommandCharacter
-    | CursorAddress
-    | CursorDown
-    | CursorHome
-    | CursorInvisible
-    | CursorLeft
-    | CursorMemAddress
-    | CursorNormal
-    | CursorRight
-    | CursorToLl
-    | CursorUp
-    | CursorVisible
-    | DeleteCharacter
-    | DeleteLine
-    | DisStatusLine
-    | DownHalfLine
-    | EnterAltCharsetMode
-    | EnterBlinkMode
-    | EnterBoldMode
-    | EnterCaMode
-    | EnterDeleteMode
-    | EnterDimMode
-    | EnterInsertMode
-    | EnterSecureMode
-    | EnterProtectedMode
-    | EnterReverseMode
-    | EnterStandoutMode
-    | EnterUnderlineMode
-    | EraseChars
-    | ExitAltCharsetMode
-    | ExitAttributeMode
-    | ExitCaMode
-    | ExitDeleteMode
-    | ExitInsertMode
-    | ExitStandoutMode
-    | ExitUnderlineMode
-    | FlashScreen
-    | FormFeed
-    | FromStatusLine
-    | Init1string
-    | Init2string
-    | Init3string
-    | InitFile
-    | InsertCharacter
-    | InsertLine
-    | InsertPadding
-    | KeyBackspace
-    | KeyCatab
-    | KeyClear
-    | KeyCtab
-    | KeyDc
-    | KeyDl
-    | KeyDown
-    | KeyEic
-    | KeyEol
-    | KeyEos
-    | KeyF0
-    | KeyF1
-    | KeyF10
-    | KeyF2
-    | KeyF3
-    | KeyF4
-    | KeyF5
-    | KeyF6
-    | KeyF7
-    | KeyF8
-    | KeyF9
-    | KeyHome
-    | KeyIc
-    | KeyIl
-    | KeyLeft
-    | KeyLl
-    | KeyNpage
-    | KeyPpage
-    | KeyRight
-    | KeySf
-    | KeySr
-    | KeyStab
-    | KeyUp
-    | KeypadLocal
-    | KeypadXmit
-    | LabF0
-    | LabF1
-    | LabF10
-    | LabF2
-    | LabF3
-    | LabF4
-    | LabF5
-    | LabF6
-    | LabF7
-    | LabF8
-    | LabF9
-    | MetaOff
-    | MetaOn
-    | Newline
-    | PadChar
-    | ParmDch
-    | ParmDeleteLine
-    | ParmDownCursor
-    | ParmIch
-    | ParmIndex
-    | ParmInsertLine
-    | ParmLeftCursor
-    | ParmRightCursor
-    | ParmRindex
-    | ParmUpCursor
-    | PkeyKey
-    | PkeyLocal
-    | PkeyXmit
-    | PrintScreen
-    | PrtrOff
-    | PrtrOn
-    | RepeatChar
-    | Reset1string
-    | Reset2string
-    | Reset3string
-    | ResetFile
-    | RestoreCursor
-    | RowAddress
-    | SaveCursor
-    | ScrollForward
-    | ScrollReverse
-    | SetAttributes
-    | SetTab
-    | SetWindow
-    | Tab
-    | ToStatusLine
-    | UnderlineChar
-    | UpHalfLine
-    | InitProg
-    | KeyA1
-    | KeyA3
-    | KeyB2
-    | KeyC1
-    | KeyC3
-    | PrtrNon
-    | CharPadding
-    | AcsChars
-    | PlabNorm
-    | KeyBtab
-    | EnterXonMode
-    | ExitXonMode
-    | EnterAmMode
-    | ExitAmMode
-    | XonCharacter
-    | XoffCharacter
-    | EnaAcs
-    | LabelOn
-    | LabelOff
-    | KeyBeg
-    | KeyCancel
-    | KeyClose
-    | KeyCommand
-    | KeyCopy
-    | KeyCreate
-    | KeyEnd
-    | KeyEnter
-    | KeyExit
-    | KeyFind
-    | KeyHelp
-    | KeyMark
-    | KeyMessage
-    | KeyMove
-    | KeyNext
-    | KeyOpen
-    | KeyOptions
-    | KeyPrevious
-    | KeyPrint
-    | KeyRedo
-    | KeyReference
-    | KeyRefresh
-    | KeyReplace
-    | KeyRestart
-    | KeyResume
-    | KeySave
-    | KeySuspend
-    | KeyUndo
-    | KeySbeg
-    | KeyScancel
-    | KeyScommand
-    | KeyScopy
-    | KeyScreate
-    | KeySdc
-    | KeySdl
-    | KeySelect
-    | KeySend
-    | KeySeol
-    | KeySexit
-    | KeySfind
-    | KeyShelp
-    | KeyShome
-    | KeySic
-    | KeySleft
-    | KeySmessage
-    | KeySmove
-    | KeySnext
-    | KeySoptions
-    | KeySprevious
-    | KeySprint
-    | KeySredo
-    | KeySreplace
-    | KeySright
-    | KeySrsume
-    | KeySsave
-    | KeySsuspend
-    | KeySundo
-    | ReqForInput
-    | KeyF11
-    | KeyF12
-    | KeyF13
-    | KeyF14
-    | KeyF15
-    | KeyF16
-    | KeyF17
-    | KeyF18
-    | KeyF19
-    | KeyF20
-    | KeyF21
-    | KeyF22
-    | KeyF23
-    | KeyF24
-    | KeyF25
-    | KeyF26
-    | KeyF27
-    | KeyF28
-    | KeyF29
-    | KeyF30
-    | KeyF31
-    | KeyF32
-    | KeyF33
-    | KeyF34
-    | KeyF35
-    | KeyF36
-    | KeyF37
-    | KeyF38
-    | KeyF39
-    | KeyF40
-    | KeyF41
-    | KeyF42
-    | KeyF43
-    | KeyF44
-    | KeyF45
-    | KeyF46
-    | KeyF47
-    | KeyF48
-    | KeyF49
-    | KeyF50
-    | KeyF51
-    | KeyF52
-    | KeyF53
-    | KeyF54
-    | KeyF55
-    | KeyF56
-    | KeyF57
-    | KeyF58
-    | KeyF59
-    | KeyF60
-    | KeyF61
-    | KeyF62
-    | KeyF63
-    | ClrBol
-    | ClearMargins
-    | SetLeftMargin
-    | SetRightMargin
-    | LabelFormat
-    | SetClock
-    | DisplayClock
-    | RemoveClock
-    | CreateWindow
-    | GotoWindow
-    | Hangup
-    | DialPhone
-    | QuickDial
-    | Tone
-    | Pulse
-    | FlashHook
-    | FixedPause
-    | WaitTone
-    | User0
-    | User1
-    | User2
-    | User3
-    | User4
-    | User5
-    | User6
-    | User7
-    | User8
-    | User9
-    | OrigPair
-    | OrigColors
-    | InitializeColor
-    | InitializePair
-    | SetColorPair
-    | SetForeground
-    | SetBackground
-    | ChangeCharPitch
-    | ChangeLinePitch
-    | ChangeResHorz
-    | ChangeResVert
-    | DefineChar
-    | EnterDoublewideMode
-    | EnterDraftQuality
-    | EnterItalicsMode
-    | EnterLeftwardMode
-    | EnterMicroMode
-    | EnterNearLetterQuality
-    | EnterNormalQuality
-    | EnterShadowMode
-    | EnterSubscriptMode
-    | EnterSuperscriptMode
-    | EnterUpwardMode
-    | ExitDoublewideMode
-    | ExitItalicsMode
-    | ExitLeftwardMode
-    | ExitMicroMode
-    | ExitShadowMode
-    | ExitSubscriptMode
-    | ExitSuperscriptMode
-    | ExitUpwardMode
-    | MicroColumnAddress
-    | MicroDown
-    | MicroLeft
-    | MicroRight
-    | MicroRowAddress
-    | MicroUp
-    | OrderOfPins
-    | ParmDownMicro
-    | ParmLeftMicro
-    | ParmRightMicro
-    | ParmUpMicro
-    | SelectCharSet
-    | SetBottomMargin
-    | SetBottomMarginParm
-    | SetLeftMarginParm
-    | SetRightMarginParm
-    | SetTopMargin
-    | SetTopMarginParm
-    | StartBitImage
-    | StartCharSetDef
-    | StopBitImage
-    | StopCharSetDef
-    | SubscriptCharacters
-    | SuperscriptCharacters
-    | TheseCauseCr
-    | ZeroMotion
-    | CharSetNames
-    | KeyMouse
-    | MouseInfo
-    | ReqMousePos
-    | GetMouse
-    | SetAForeground
-    | SetABackground
-    | PkeyPlab
-    | DeviceType
-    | CodeSetInit
-    | Set0DesSeq
-    | Set1DesSeq
-    | Set2DesSeq
-    | Set3DesSeq
-    | SetLrMargin
-    | SetTbMargin
-    | BitImageRepeat
-    | BitImageNewline
-    | BitImageCarriageReturn
-    | ColorNames
-    | DefineBitImageRegion
-    | EndBitImageRegion
-    | SetColorBand
-    | SetPageLength
-    | DisplayPcChar
-    | EnterPcCharsetMode
-    | ExitPcCharsetMode
-    | EnterScancodeMode
-    | ExitScancodeMode
-    | PcTermOptions
-    | ScancodeEscape
-    | AltScancodeEsc
-    | EnterHorizontalHlMode
-    | EnterLeftHlMode
-    | EnterLowHlMode
-    | EnterRightHlMode
-    | EnterTopHlMode
-    | EnterVerticalHlMode
-    | SetAAttributes
-    | SetPglenInch
-    | TermcapInit2
-    | TermcapReset
-    | LinefeedIfNotLf
-    | BackspaceIfNotBs
-    | OtherNonFunctionKeys
-    | ArrowKeyMap
-    | AcsUlcorner
-    | AcsLlcorner
-    | AcsUrcorner
-    | AcsLrcorner
-    | AcsLtee
-    | AcsRtee
-    | AcsBtee
-    | AcsTtee
-    | AcsHline
-    | AcsVline
-    | AcsPlus
-    | MemoryLock
-    | MemoryUnlock
-    | BoxChars1
-    deriving (Ord, Eq, Enum, Bounded, Show)
diff --git a/System/Terminfo/DBParse.hs b/System/Terminfo/DBParse.hs
deleted file mode 100644
--- a/System/Terminfo/DBParse.hs
+++ /dev/null
@@ -1,126 +0,0 @@
-{-# LANGUAGE RecordWildCards #-}
-
--- |
--- Module      :  System.Terminfo.DBParse
--- Copyright   :  (c) Bryan Richter (2013)
--- License     :  BSD-style
--- 
--- Maintainer  :  bryan.richter@gmail.com
---
--- An internal module encapsulating methods for parsing a terminfo file as
--- generated by tic(1). The primary reference is the term(5) manpage.
---
-
-module System.Terminfo.DBParse
-    ( parseDB
-    ) where
-
-import Control.Applicative ((<$>), (<*>))
-import Control.Arrow ((***))
-import qualified Control.Arrow as Arr
-import Control.Monad ((<=<), when, void)
-import Data.Attoparsec as A
-import Data.ByteString (ByteString)
-import qualified Data.ByteString as B
-import Data.Char (chr)
-import qualified Data.Map.Lazy as M
-import Data.Word (Word16)
-
-import System.Terminfo.Types
-
--- | term(5) defines a short integer as two 8-bit bytes, so:
-type ShortInt = Word16
-
--- | short ints are stored little-endian.
-shortInt :: Integral a => ShortInt -> Parser a
-shortInt i = word8 first >> word8 second >> return (fromIntegral i)
-  where
-    (second, first) = (fromIntegral *** fromIntegral) $ i `divMod` 256
-
--- | short ints are stored little-endian.
---
--- (-1) is represented by the two bytes 0o377 0o377.
---
--- Return type is Int so I can include (-1) in the possible outputs. I
--- wonder if I will regret this.
-anyShortInt :: Parser Int
-anyShortInt = do
-    first <- fromIntegral <$> anyWord8
-    second <- fromIntegral <$> anyWord8
-    return $ if first == 0o377 && second == 0o377
-       then (-1)
-       else 256*second + first
-
-parseDB :: ByteString -> Either String TIDatabase
-parseDB = parseOnly tiDatabase
-
-tiDatabase :: Parser TIDatabase
-tiDatabase = do
-    Header{..} <- header
-    -- Ignore names
-    _ <- A.take namesSize
-    bools <- boolCaps boolSize
-    -- Align on an even byte
-    when (odd boolSize) (void $ A.take 1)
-    nums <- numCaps numIntegers
-    strs <- stringCaps numOffsets stringSize
-    -- TODO: extended info
-    return $ TIDatabase bools nums strs
-
-boolCaps :: Int -- ^ Number of caps
-         -> Parser TCBMap
-boolCaps =
-    return . TCBMap . M.fromList . zip keys . map (== 1) . B.unpack
-        <=< A.take
-  where
-    {-keys :: [BoolTermCap]-}
-    keys = [minBound ..]
-
--- Negative values indicate missing capability.
-numCaps :: Int -- ^ Number of caps
-        -> Parser TCNMap
-numCaps = return . TCNMap . M.fromList . filter notNeg . zip keys
-    <=< flip A.count anyShortInt
-  where
-    notNeg = ((/= -1) . snd)
-    {-keys :: [BoolTermCap]-}
-    keys = [minBound ..]
-
-stringCaps :: Int -- ^ Number of caps
-           -> Int -- ^ Size of table
-           -> Parser TCSMap
-stringCaps numOffsets stringSize = do
-    offs <- A.count numOffsets anyShortInt
-    stringTable <- A.take stringSize
-    return
-        $ TCSMap $ M.fromList $ map (parseValue stringTable)
-        $ filter notNeg $ zip keys offs
-  where
-    notNeg = ((/= -1) . snd)
-    keys = [minBound ..]
-    parseValue tbl = Arr.second $ parseString tbl
-    parseString table offset =
-        asString
-        $ B.takeWhile (/= 0)  -- null-terminated
-        $ B.drop offset table -- starts at offset
-    asString = map (chr . fromIntegral) . B.unpack
-
--- | the magic number for term files
-magic :: Parser Int
-magic = shortInt 0o432 <?> "Not a terminfo file (bad magic)"
-
-data Header = Header
-     { namesSize :: Int
-     , boolSize :: Int
-     , numIntegers :: Int
-     , numOffsets :: Int
-     , stringSize :: Int
-     }
-     deriving (Show)
-
-header :: Parser Header
-header = magic >> Header <$> anyShortInt
-                         <*> anyShortInt
-                         <*> anyShortInt
-                         <*> anyShortInt
-                         <*> anyShortInt
diff --git a/System/Terminfo/Internal.hs b/System/Terminfo/Internal.hs
deleted file mode 100644
--- a/System/Terminfo/Internal.hs
+++ /dev/null
@@ -1,67 +0,0 @@
-module System.Terminfo.Internal
-    ( terminfoDBLocs
-    , locationsPure
-    , parseTDVar
-    ) where
-
-import Control.Applicative ((<$>), (<*>), pure)
-import Control.Error
-import System.Environment (lookupEnv)
-import System.FilePath
-
-terminfoDBLocs :: IO [FilePath]
-terminfoDBLocs = locationsPure
-    <$> lookupEnv "TERMINFO"
-    <*> (lookupEnv "HOME" <$$/> ".terminfo")
-    <*> lookupEnv "TERMINFO_DIRS"
-    <*> pure ["/lib/terminfo", "/usr/share/terminfo"]
-
-
-(<$/>) :: Functor f => f FilePath -> FilePath -> f FilePath
-fa <$/> b = (</> b) <$> fa
-infixr 4 <$/>
-
-(<$$/>) :: (Functor f, Functor g)
-        => f (g FilePath)
-        -> FilePath
-        -> f (g FilePath)
-ffa <$$/> b = fmap (<$/> b) ffa
-infixr 4 <$$/>
-
--- | I hate this name. There is undoubtedly a better way of structuring all
--- of this, starting way up at 'dirTreeDB'.
-locationsPure :: Maybe FilePath -- ^ Override directory
-              -> Maybe FilePath -- ^ $HOME
-              -> Maybe String   -- ^ $TERMINFO_DIRS
-              -> [FilePath]     -- ^ Defaults
-              -> [FilePath]
-locationsPure ovr usr termdirs defs = case ovr of
-    Just override -> [override]
-    Nothing       -> catMaybes [usr] ++ system
-
-  where
-    system = case termdirs of
-        Just list -> parseTDVar defs list
-        Nothing   -> defs
-
-parseTDVar :: [String] -> String -> [String]
-parseTDVar defs = replace "" defs . split ':'
-
--- | Replace an element with multiple replacements
-replace :: Eq a => a -> [a] -> [a] -> [a]
-replace old news = foldr (\x acc -> if x == old
-                                       then news ++ acc
-                                       else x : acc)
-                         []
-
--- | split, as seen in ByteString and Text, but for Strings.
-split :: Char -> String -> [String]
-split s = foldr go [[]]
-  where
-    go c acc = if c /= s
-                  then unshift c acc
-                  else "" : acc
-
-    -- | /perldoc -f unshift/
-    unshift c (xs:xss) = (c:xs) : xss
-    unshift c []       = [[c]]
diff --git a/System/Terminfo/Types.hs b/System/Terminfo/Types.hs
deleted file mode 100644
--- a/System/Terminfo/Types.hs
+++ /dev/null
@@ -1,20 +0,0 @@
-module System.Terminfo.Types
-    ( TIDatabase(..)
-    , TCBMap(..)
-    , TCNMap(..)
-    , TCSMap(..)
-    ) where
-
-import Data.Map.Lazy (Map)
-
-import System.Terminfo.Caps
-
-data TCBMap = TCBMap (Map BoolTermCap Bool)
-    deriving (Show)
-data TCNMap = TCNMap (Map NumTermCap Int)
-    deriving (Show)
-data TCSMap = TCSMap (Map StrTermCap String)
-    deriving (Show)
-
-data TIDatabase = TIDatabase TCBMap TCNMap TCSMap
-    deriving (Show)
diff --git a/src/System/Terminfo.hs b/src/System/Terminfo.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Terminfo.hs
@@ -0,0 +1,178 @@
+{-# LANGUAGE CPP #-}
+-- |
+-- Module      :  System.Terminfo
+-- Copyright   :  (c) Bryan Richter (2013)
+-- License     :  BSD-style
+-- Maintainer  :  bryan.richter@gmail.com
+--
+-- This is a pure-Haskell (no FFI) module for accessing terminfo databases,
+-- which contain characteristics, or capabilities, for the various
+-- terminals such as screen, vt100, or xterm. Among other things, the
+-- capabilities include the idiosyncratic character sequences needed to
+-- send commands to the terminal. These commands include things like cursor
+-- movement.
+--
+-- For a deeper understanding of terminfo, consult the man pages for
+-- term(5) and terminfo(5).
+--
+-- There are three parts to this module: acquiring a terminfo database,
+-- querying the database, and defining the capabilities.
+--
+-- This module is dead simple, so a single example will hopefully suffice
+-- to demonstrate its usage.
+--
+-- @
+-- import System.Terminfo
+-- import System.Terminfo.Caps as C
+-- uglyExample :: IO (Maybe Int)
+-- uglyExample = do
+--     term \<- fromJust \<$> lookupEnv \"TERM\"
+--     db \<- 'acquireDatabase' term
+--     let maxColors (Right d) = 'queryNumTermCap' d C.'MaxColors'
+--     return $ maxColors db
+-- @
+--
+-- >>> uglyExample
+-- Just 256
+--
+
+module System.Terminfo (
+    -- * Acquiring a Database
+      acquireDatabase
+    -- * Querying Capabilities
+    -- $queryFuncs
+    , queryBoolTermCap
+    , queryNumTermCap
+    , queryStrTermCap
+    -- * The Capabilities
+    -- $capabilities
+
+    -- * The Database Type
+    , TIDatabase
+
+    ) where
+
+#if MIN_VERSION_base(4,8,0)
+import Control.Applicative ((<|>))
+#else
+import Control.Applicative ((<$>), (<|>))
+#endif
+import Control.Error
+import Control.Monad ((<=<), filterM)
+import qualified Data.ByteString as B
+import qualified Data.Map.Lazy as M
+import System.Directory
+import System.FilePath
+import System.IO
+
+import System.Terminfo.Types
+import System.Terminfo.DBParse
+import System.Terminfo.Internal (terminfoDBLocs)
+import System.Terminfo.Caps
+
+#if MIN_VERSION_base(4,8,0)
+except :: m (Either e a) -> ExceptT e m a
+except = ExceptT
+#else
+type ExceptT = EitherT
+runExceptT :: EitherT e m a -> m (Either e a)
+runExceptT = runEitherT
+except :: m (Either e a) -> EitherT e m a
+except = EitherT
+#endif
+
+data DBType = BerkeleyDB | DirTreeDB
+    deriving(Show)
+
+-- Old MacDonald had a farm...
+type EIO = ExceptT String IO
+
+acquireDatabase
+    :: String -- ^ System name
+    -> IO (Either String TIDatabase)
+       -- ^ A database object for the terminal, if it exists.
+acquireDatabase = runExceptT . (parseDBFile <=< findDBFile)
+
+findDBFile :: String -> EIO (DBType, FilePath)
+findDBFile term = case term of
+    (c:_) -> dbFileM c term `orLeft` "No terminfo db found"
+    _     -> hoistEither $ Left "User specified null terminal name"
+  where
+    orLeft = flip noteT
+    dbFileM c t = dirTreeDB c t <|> berkeleyDB
+
+-- | Not implemented
+berkeleyDB :: MaybeT IO (DBType, FilePath)
+berkeleyDB = nothing
+
+dirTreeDB :: Char -> String -> MaybeT IO (DBType, FilePath)
+dirTreeDB c term = MaybeT $ do
+    path <- findFirst =<< map (</> [c] </> term) <$> terminfoDBLocs
+    return $ (,) DirTreeDB <$> path
+
+findFirst :: [FilePath] -> IO (Maybe FilePath)
+findFirst = fmap headMay . filterM doesFileExist
+
+parseDBFile :: (DBType, FilePath) -> EIO TIDatabase
+parseDBFile (db, f) = case db of
+    DirTreeDB -> extractDirTreeDB f
+    BerkeleyDB -> hoistEither
+        $ Left "BerkeleyDB support not yet implemented"
+
+-- | Extract a 'TIDatabase' from the specified file. IO exceptions are
+-- left to their own devices.
+extractDirTreeDB :: FilePath
+                 -> EIO TIDatabase
+extractDirTreeDB =
+    hoistEither . parseDB
+    <=< rightT . B.hGetContents
+    <=< rightT . flip openBinaryFile ReadMode
+  where
+    rightT = except . fmap Right
+
+queryBoolTermCap :: TIDatabase
+                 -> BoolTermCap
+                 -> Bool
+queryBoolTermCap (TIDatabase (TCBMap vals) _ _) cap =
+    fromMaybe False $ M.lookup cap vals
+
+queryNumTermCap :: TIDatabase
+                -> NumTermCap
+                -> Maybe Int
+queryNumTermCap (TIDatabase _ (TCNMap vals) _) cap = M.lookup cap vals
+
+-- | As this is a dead simple module, no \'smart\' handling of the
+-- returned string is implemented. In particular, placeholders for
+-- buffer characters and command arguments are left as-is. This will be
+-- rectified eventually, probably in a separate module.
+queryStrTermCap :: TIDatabase
+                -> StrTermCap
+                -> Maybe String
+queryStrTermCap (TIDatabase _ _ (TCSMap vals)) cap = M.lookup cap vals
+
+--
+-- DOCUMENTATION
+--
+
+
+
+-- $queryFuncs
+--
+-- For each of these three actions, the first argument is the database to
+-- query, and the second argument is the capability to look up.
+--
+-- I'm not super proud of this interface, but it's the best I can manage at
+-- present without requiring lots of mostly-empty case expressions. Perhaps
+-- someone will suggest a more interesting solution.
+
+-- $capabilities
+--
+-- /see/ "System.Terminfo.Caps"
+--
+-- There are no less than 497 capabilities specified in term.h on my
+-- Intel-based Ubuntu 12.04 notebook (slightly fewer in the terminfo(5) man
+-- page). The naive way of making these available to the user is as data
+-- constructors, and that is what I have done here.
+--
+-- The number of constructors absolutely crushes the namespace. I have
+-- sequestered them into their own module to try to alleviate the pain.
diff --git a/src/System/Terminfo/Caps.hs b/src/System/Terminfo/Caps.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Terminfo/Caps.hs
@@ -0,0 +1,519 @@
+-- | There is an egregious number of capabilities. They are sequestered in
+-- this module to preserve namespace sanity.
+--
+-- For descriptions of these, consult terminfo(5).
+
+module System.Terminfo.Caps (
+    -- * Boolean
+      BoolTermCap(..)
+    -- * Numeric
+    , NumTermCap(..)
+    -- * String
+    , StrTermCap(..)
+    ) where
+
+data BoolTermCap
+    = AutoLeftMargin
+    | AutoRightMargin
+    | NoEscCtlc
+    | CeolStandoutGlitch
+    | EatNewlineGlitch
+    | EraseOverstrike
+    | GenericType
+    | HardCopy
+    | HasMetaKey
+    | HasStatusLine
+    | InsertNullGlitch
+    | MemoryAbove
+    | MemoryBelow
+    | MoveInsertMode
+    | MoveStandoutMode
+    | OverStrike
+    | StatusLineEscOk
+    | DestTabsMagicSmso
+    | TildeGlitch
+    | TransparentUnderline
+    | XonXoff
+    | NeedsXonXoff
+    | PrtrSilent
+    | HardCursor
+    | NonRevRmcup
+    | NoPadChar
+    | NonDestScrollRegion
+    | CanChange
+    | BackColorErase
+    | HueLightnessSaturation
+    | ColAddrGlitch
+    | CrCancelsMicroMode
+    | HasPrintWheel
+    | RowAddrGlitch
+    | SemiAutoRightMargin
+    | CpiChangesRes
+    | LpiChangesRes
+    | BackspacesWithBs
+    | CrtNoScrolling
+    | NoCorrectlyWorkingCr
+    | GnuHasMetaKey
+    | LinefeedIsNewline
+    | HasHardwareTabs
+    | ReturnDoesClrEol
+    deriving (Ord, Eq, Enum, Bounded, Show)
+
+data NumTermCap
+    = Columns
+    | InitTabs
+    | Lines
+    | LinesOfMemory
+    | MagicCookieGlitch
+    | PaddingBaudRate
+    | VirtualTerminal
+    | WidthStatusLine
+    | NumLabels
+    | LabelHeight
+    | LabelWidth
+    | MaxAttributes
+    | MaximumWindows
+    | MaxColors
+    | MaxPairs
+    | NoColorVideo
+    | BufferCapacity
+    | DotVertSpacing
+    | DotHorzSpacing
+    | MaxMicroAddress
+    | MaxMicroJump
+    | MicroColSize
+    | MicroLineSize
+    | NumberOfPins
+    | OutputResChar
+    | OutputResLine
+    | OutputResHorzInch
+    | OutputResVertInch
+    | PrintRate
+    | WideCharSize
+    | Buttons
+    | BitImageEntwining
+    | BitImageType
+    | MagicCookieGlitchUl
+    | CarriageReturnDelay
+    | NewLineDelay
+    | BackspaceDelay
+    | HorizontalTabDelay
+    | NumberOfFunctionKeys
+    deriving (Ord, Eq, Enum, Bounded, Show)
+
+data StrTermCap
+    = BackTab
+    | Bell
+    | CarriageReturn
+    | ChangeScrollRegion
+    | ClearAllTabs
+    | ClearScreen
+    | ClrEol
+    | ClrEos
+    | ColumnAddress
+    | CommandCharacter
+    | CursorAddress
+    | CursorDown
+    | CursorHome
+    | CursorInvisible
+    | CursorLeft
+    | CursorMemAddress
+    | CursorNormal
+    | CursorRight
+    | CursorToLl
+    | CursorUp
+    | CursorVisible
+    | DeleteCharacter
+    | DeleteLine
+    | DisStatusLine
+    | DownHalfLine
+    | EnterAltCharsetMode
+    | EnterBlinkMode
+    | EnterBoldMode
+    | EnterCaMode
+    | EnterDeleteMode
+    | EnterDimMode
+    | EnterInsertMode
+    | EnterSecureMode
+    | EnterProtectedMode
+    | EnterReverseMode
+    | EnterStandoutMode
+    | EnterUnderlineMode
+    | EraseChars
+    | ExitAltCharsetMode
+    | ExitAttributeMode
+    | ExitCaMode
+    | ExitDeleteMode
+    | ExitInsertMode
+    | ExitStandoutMode
+    | ExitUnderlineMode
+    | FlashScreen
+    | FormFeed
+    | FromStatusLine
+    | Init1string
+    | Init2string
+    | Init3string
+    | InitFile
+    | InsertCharacter
+    | InsertLine
+    | InsertPadding
+    | KeyBackspace
+    | KeyCatab
+    | KeyClear
+    | KeyCtab
+    | KeyDc
+    | KeyDl
+    | KeyDown
+    | KeyEic
+    | KeyEol
+    | KeyEos
+    | KeyF0
+    | KeyF1
+    | KeyF10
+    | KeyF2
+    | KeyF3
+    | KeyF4
+    | KeyF5
+    | KeyF6
+    | KeyF7
+    | KeyF8
+    | KeyF9
+    | KeyHome
+    | KeyIc
+    | KeyIl
+    | KeyLeft
+    | KeyLl
+    | KeyNpage
+    | KeyPpage
+    | KeyRight
+    | KeySf
+    | KeySr
+    | KeyStab
+    | KeyUp
+    | KeypadLocal
+    | KeypadXmit
+    | LabF0
+    | LabF1
+    | LabF10
+    | LabF2
+    | LabF3
+    | LabF4
+    | LabF5
+    | LabF6
+    | LabF7
+    | LabF8
+    | LabF9
+    | MetaOff
+    | MetaOn
+    | Newline
+    | PadChar
+    | ParmDch
+    | ParmDeleteLine
+    | ParmDownCursor
+    | ParmIch
+    | ParmIndex
+    | ParmInsertLine
+    | ParmLeftCursor
+    | ParmRightCursor
+    | ParmRindex
+    | ParmUpCursor
+    | PkeyKey
+    | PkeyLocal
+    | PkeyXmit
+    | PrintScreen
+    | PrtrOff
+    | PrtrOn
+    | RepeatChar
+    | Reset1string
+    | Reset2string
+    | Reset3string
+    | ResetFile
+    | RestoreCursor
+    | RowAddress
+    | SaveCursor
+    | ScrollForward
+    | ScrollReverse
+    | SetAttributes
+    | SetTab
+    | SetWindow
+    | Tab
+    | ToStatusLine
+    | UnderlineChar
+    | UpHalfLine
+    | InitProg
+    | KeyA1
+    | KeyA3
+    | KeyB2
+    | KeyC1
+    | KeyC3
+    | PrtrNon
+    | CharPadding
+    | AcsChars
+    | PlabNorm
+    | KeyBtab
+    | EnterXonMode
+    | ExitXonMode
+    | EnterAmMode
+    | ExitAmMode
+    | XonCharacter
+    | XoffCharacter
+    | EnaAcs
+    | LabelOn
+    | LabelOff
+    | KeyBeg
+    | KeyCancel
+    | KeyClose
+    | KeyCommand
+    | KeyCopy
+    | KeyCreate
+    | KeyEnd
+    | KeyEnter
+    | KeyExit
+    | KeyFind
+    | KeyHelp
+    | KeyMark
+    | KeyMessage
+    | KeyMove
+    | KeyNext
+    | KeyOpen
+    | KeyOptions
+    | KeyPrevious
+    | KeyPrint
+    | KeyRedo
+    | KeyReference
+    | KeyRefresh
+    | KeyReplace
+    | KeyRestart
+    | KeyResume
+    | KeySave
+    | KeySuspend
+    | KeyUndo
+    | KeySbeg
+    | KeyScancel
+    | KeyScommand
+    | KeyScopy
+    | KeyScreate
+    | KeySdc
+    | KeySdl
+    | KeySelect
+    | KeySend
+    | KeySeol
+    | KeySexit
+    | KeySfind
+    | KeyShelp
+    | KeyShome
+    | KeySic
+    | KeySleft
+    | KeySmessage
+    | KeySmove
+    | KeySnext
+    | KeySoptions
+    | KeySprevious
+    | KeySprint
+    | KeySredo
+    | KeySreplace
+    | KeySright
+    | KeySrsume
+    | KeySsave
+    | KeySsuspend
+    | KeySundo
+    | ReqForInput
+    | KeyF11
+    | KeyF12
+    | KeyF13
+    | KeyF14
+    | KeyF15
+    | KeyF16
+    | KeyF17
+    | KeyF18
+    | KeyF19
+    | KeyF20
+    | KeyF21
+    | KeyF22
+    | KeyF23
+    | KeyF24
+    | KeyF25
+    | KeyF26
+    | KeyF27
+    | KeyF28
+    | KeyF29
+    | KeyF30
+    | KeyF31
+    | KeyF32
+    | KeyF33
+    | KeyF34
+    | KeyF35
+    | KeyF36
+    | KeyF37
+    | KeyF38
+    | KeyF39
+    | KeyF40
+    | KeyF41
+    | KeyF42
+    | KeyF43
+    | KeyF44
+    | KeyF45
+    | KeyF46
+    | KeyF47
+    | KeyF48
+    | KeyF49
+    | KeyF50
+    | KeyF51
+    | KeyF52
+    | KeyF53
+    | KeyF54
+    | KeyF55
+    | KeyF56
+    | KeyF57
+    | KeyF58
+    | KeyF59
+    | KeyF60
+    | KeyF61
+    | KeyF62
+    | KeyF63
+    | ClrBol
+    | ClearMargins
+    | SetLeftMargin
+    | SetRightMargin
+    | LabelFormat
+    | SetClock
+    | DisplayClock
+    | RemoveClock
+    | CreateWindow
+    | GotoWindow
+    | Hangup
+    | DialPhone
+    | QuickDial
+    | Tone
+    | Pulse
+    | FlashHook
+    | FixedPause
+    | WaitTone
+    | User0
+    | User1
+    | User2
+    | User3
+    | User4
+    | User5
+    | User6
+    | User7
+    | User8
+    | User9
+    | OrigPair
+    | OrigColors
+    | InitializeColor
+    | InitializePair
+    | SetColorPair
+    | SetForeground
+    | SetBackground
+    | ChangeCharPitch
+    | ChangeLinePitch
+    | ChangeResHorz
+    | ChangeResVert
+    | DefineChar
+    | EnterDoublewideMode
+    | EnterDraftQuality
+    | EnterItalicsMode
+    | EnterLeftwardMode
+    | EnterMicroMode
+    | EnterNearLetterQuality
+    | EnterNormalQuality
+    | EnterShadowMode
+    | EnterSubscriptMode
+    | EnterSuperscriptMode
+    | EnterUpwardMode
+    | ExitDoublewideMode
+    | ExitItalicsMode
+    | ExitLeftwardMode
+    | ExitMicroMode
+    | ExitShadowMode
+    | ExitSubscriptMode
+    | ExitSuperscriptMode
+    | ExitUpwardMode
+    | MicroColumnAddress
+    | MicroDown
+    | MicroLeft
+    | MicroRight
+    | MicroRowAddress
+    | MicroUp
+    | OrderOfPins
+    | ParmDownMicro
+    | ParmLeftMicro
+    | ParmRightMicro
+    | ParmUpMicro
+    | SelectCharSet
+    | SetBottomMargin
+    | SetBottomMarginParm
+    | SetLeftMarginParm
+    | SetRightMarginParm
+    | SetTopMargin
+    | SetTopMarginParm
+    | StartBitImage
+    | StartCharSetDef
+    | StopBitImage
+    | StopCharSetDef
+    | SubscriptCharacters
+    | SuperscriptCharacters
+    | TheseCauseCr
+    | ZeroMotion
+    | CharSetNames
+    | KeyMouse
+    | MouseInfo
+    | ReqMousePos
+    | GetMouse
+    | SetAForeground
+    | SetABackground
+    | PkeyPlab
+    | DeviceType
+    | CodeSetInit
+    | Set0DesSeq
+    | Set1DesSeq
+    | Set2DesSeq
+    | Set3DesSeq
+    | SetLrMargin
+    | SetTbMargin
+    | BitImageRepeat
+    | BitImageNewline
+    | BitImageCarriageReturn
+    | ColorNames
+    | DefineBitImageRegion
+    | EndBitImageRegion
+    | SetColorBand
+    | SetPageLength
+    | DisplayPcChar
+    | EnterPcCharsetMode
+    | ExitPcCharsetMode
+    | EnterScancodeMode
+    | ExitScancodeMode
+    | PcTermOptions
+    | ScancodeEscape
+    | AltScancodeEsc
+    | EnterHorizontalHlMode
+    | EnterLeftHlMode
+    | EnterLowHlMode
+    | EnterRightHlMode
+    | EnterTopHlMode
+    | EnterVerticalHlMode
+    | SetAAttributes
+    | SetPglenInch
+    | TermcapInit2
+    | TermcapReset
+    | LinefeedIfNotLf
+    | BackspaceIfNotBs
+    | OtherNonFunctionKeys
+    | ArrowKeyMap
+    | AcsUlcorner
+    | AcsLlcorner
+    | AcsUrcorner
+    | AcsLrcorner
+    | AcsLtee
+    | AcsRtee
+    | AcsBtee
+    | AcsTtee
+    | AcsHline
+    | AcsVline
+    | AcsPlus
+    | MemoryLock
+    | MemoryUnlock
+    | BoxChars1
+    deriving (Ord, Eq, Enum, Bounded, Show)
diff --git a/src/System/Terminfo/DBParse.hs b/src/System/Terminfo/DBParse.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Terminfo/DBParse.hs
@@ -0,0 +1,129 @@
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE CPP #-}
+
+-- |
+-- Module      :  System.Terminfo.DBParse
+-- Copyright   :  (c) Bryan Richter (2013)
+-- License     :  BSD-style
+-- 
+-- Maintainer  :  bryan.richter@gmail.com
+--
+-- An internal module encapsulating methods for parsing a terminfo file as
+-- generated by tic(1). The primary reference is the term(5) manpage.
+--
+
+module System.Terminfo.DBParse
+    ( parseDB
+    ) where
+
+#if ! MIN_VERSION_base(4,8,0)
+import Control.Applicative ((<$>), (<*>))
+#endif
+import Control.Arrow ((***))
+import qualified Control.Arrow as Arr
+import Control.Monad ((<=<), when, void)
+import Data.Attoparsec.ByteString as A
+import Data.ByteString (ByteString)
+import qualified Data.ByteString as B
+import Data.Char (chr)
+import qualified Data.Map.Lazy as M
+import Data.Word (Word16)
+
+import System.Terminfo.Types
+
+-- | term(5) defines a short integer as two 8-bit bytes, so:
+type ShortInt = Word16
+
+-- | short ints are stored little-endian.
+shortInt :: Integral a => ShortInt -> Parser a
+shortInt i = word8 first >> word8 second >> return (fromIntegral i)
+  where
+    (second, first) = (fromIntegral *** fromIntegral) $ i `divMod` 256
+
+-- | short ints are stored little-endian.
+--
+-- (-1) is represented by the two bytes 0o377 0o377.
+--
+-- Return type is Int so I can include (-1) in the possible outputs. I
+-- wonder if I will regret this.
+anyShortInt :: Parser Int
+anyShortInt = do
+    first <- fromIntegral <$> anyWord8
+    second <- fromIntegral <$> anyWord8
+    return $ if first == 0o377 && second == 0o377
+       then (-1)
+       else 256*second + first
+
+parseDB :: ByteString -> Either String TIDatabase
+parseDB = parseOnly tiDatabase
+
+tiDatabase :: Parser TIDatabase
+tiDatabase = do
+    Header{..} <- header
+    -- Ignore names
+    _ <- A.take namesSize
+    bools <- boolCaps boolSize
+    -- Align on an even byte
+    when (odd boolSize) (void $ A.take 1)
+    nums <- numCaps numIntegers
+    strs <- stringCaps numOffsets stringSize
+    -- TODO: extended info
+    return $ TIDatabase bools nums strs
+
+boolCaps :: Int -- ^ Number of caps
+         -> Parser TCBMap
+boolCaps =
+    return . TCBMap . M.fromList . zip keys . map (== 1) . B.unpack
+        <=< A.take
+  where
+    {-keys :: [BoolTermCap]-}
+    keys = [minBound ..]
+
+-- Negative values indicate missing capability.
+numCaps :: Int -- ^ Number of caps
+        -> Parser TCNMap
+numCaps = return . TCNMap . M.fromList . filter notNeg . zip keys
+    <=< flip A.count anyShortInt
+  where
+    notNeg = ((/= -1) . snd)
+    {-keys :: [BoolTermCap]-}
+    keys = [minBound ..]
+
+stringCaps :: Int -- ^ Number of caps
+           -> Int -- ^ Size of table
+           -> Parser TCSMap
+stringCaps numOffsets stringSize = do
+    offs <- A.count numOffsets anyShortInt
+    stringTable <- A.take stringSize
+    return
+        $ TCSMap $ M.fromList $ map (parseValue stringTable)
+        $ filter notNeg $ zip keys offs
+  where
+    notNeg = ((/= -1) . snd)
+    keys = [minBound ..]
+    parseValue tbl = Arr.second $ parseString tbl
+    parseString table offset =
+        asString
+        $ B.takeWhile (/= 0)  -- null-terminated
+        $ B.drop offset table -- starts at offset
+    asString = map (chr . fromIntegral) . B.unpack
+
+-- | the magic number for term files
+magic :: Parser Int
+magic = shortInt 0o432 <?> "Not a terminfo file (bad magic)"
+
+data Header = Header
+     { namesSize :: !Int
+     , boolSize :: !Int
+     , numIntegers :: !Int
+     , numOffsets :: !Int
+     , stringSize :: !Int
+     }
+     deriving (Show)
+
+header :: Parser Header
+header = magic >> Header <$> anyShortInt
+                         <*> anyShortInt
+                         <*> anyShortInt
+                         <*> anyShortInt
+                         <*> anyShortInt
diff --git a/src/System/Terminfo/Internal.hs b/src/System/Terminfo/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Terminfo/Internal.hs
@@ -0,0 +1,70 @@
+{-# LANGUAGE CPP #-}
+module System.Terminfo.Internal
+    ( terminfoDBLocs
+    , locationsPure
+    , parseTDVar
+    ) where
+
+#if ! MIN_VERSION_base(4,8,0)
+import Control.Applicative ((<$>), (<*>), pure)
+#endif
+import Control.Error
+import System.Environment (lookupEnv)
+import System.FilePath
+
+terminfoDBLocs :: IO [FilePath]
+terminfoDBLocs = locationsPure
+    <$> lookupEnv "TERMINFO"
+    <*> (lookupEnv "HOME" <$$/> ".terminfo")
+    <*> lookupEnv "TERMINFO_DIRS"
+    <*> pure ["/lib/terminfo", "/usr/share/terminfo"]
+
+
+(<$/>) :: Functor f => f FilePath -> FilePath -> f FilePath
+fa <$/> b = (</> b) <$> fa
+infixr 4 <$/>
+
+(<$$/>) :: (Functor f, Functor g)
+        => f (g FilePath)
+        -> FilePath
+        -> f (g FilePath)
+ffa <$$/> b = fmap (<$/> b) ffa
+infixr 4 <$$/>
+
+-- | I hate this name. There is undoubtedly a better way of structuring all
+-- of this, starting way up at 'dirTreeDB'.
+locationsPure :: Maybe FilePath -- ^ Override directory
+              -> Maybe FilePath -- ^ $HOME
+              -> Maybe String   -- ^ $TERMINFO_DIRS
+              -> [FilePath]     -- ^ Defaults
+              -> [FilePath]
+locationsPure ovr usr termdirs defs = case ovr of
+    Just override -> [override]
+    Nothing       -> catMaybes [usr] ++ system
+
+  where
+    system = case termdirs of
+        Just list -> parseTDVar defs list
+        Nothing   -> defs
+
+parseTDVar :: [String] -> String -> [String]
+parseTDVar defs = replace "" defs . split ':'
+
+-- | Replace an element with multiple replacements
+replace :: Eq a => a -> [a] -> [a] -> [a]
+replace old news = foldr (\x acc -> if x == old
+                                       then news ++ acc
+                                       else x : acc)
+                         []
+
+-- | split, as seen in ByteString and Text, but for Strings.
+split :: Char -> String -> [String]
+split s = foldr go [[]]
+  where
+    go c acc = if c /= s
+                  then unshift c acc
+                  else "" : acc
+
+    -- | /perldoc -f unshift/
+    unshift c (xs:xss) = (c:xs) : xss
+    unshift c []       = [[c]]
diff --git a/src/System/Terminfo/Types.hs b/src/System/Terminfo/Types.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Terminfo/Types.hs
@@ -0,0 +1,20 @@
+module System.Terminfo.Types
+    ( TIDatabase(..)
+    , TCBMap(..)
+    , TCNMap(..)
+    , TCSMap(..)
+    ) where
+
+import Data.Map.Lazy (Map)
+
+import System.Terminfo.Caps
+
+data TCBMap = TCBMap (Map BoolTermCap Bool)
+    deriving (Show)
+data TCNMap = TCNMap (Map NumTermCap Int)
+    deriving (Show)
+data TCSMap = TCSMap (Map StrTermCap String)
+    deriving (Show)
+
+data TIDatabase = TIDatabase TCBMap TCNMap TCSMap
+    deriving (Show)
diff --git a/terminfo-hs.cabal b/terminfo-hs.cabal
--- a/terminfo-hs.cabal
+++ b/terminfo-hs.cabal
@@ -1,20 +1,19 @@
-name:                terminfo-hs
-version:             0.1.0.1
-synopsis:            A pure-Haskell (no FFI) module for accessing terminfo databases
-description:         This module can acquire terminfo databases and query
-                     them for terminal capabilities. For details of
-                     terminfo, consult the man pages for term(5) and
-                     terminfo(5).
+name: terminfo-hs
+version: 0.2.0
+synopsis: A pure-Haskell (no FFI) module for accessing terminfo databases
+description:
+    This module can acquire terminfo databases and query them for terminal
+    capabilities. For details of terminfo, consult the man pages for
+    term(5) and terminfo(5).
 
-                     This package is dead simple, and doesn't do anything
-                     fancy with the capabilities themselves. It merely
-                     provides a means for accessing them.
+    This package is dead simple, and doesn't do anything fancy with the
+    capabilities themselves. It merely provides a means for accessing them.
 
 license:             BSD3
 license-file:        LICENSE
 author:              Bryan Richter
 maintainer:          bryan.richter@gmail.com
-copyright:           Bryan Richter, 2013
+copyright:           Bryan Richter, 2013–2015
 category:            System, Terminal
 build-type:          Simple
 cabal-version:       >=1.8
@@ -25,22 +24,31 @@
 
 source-repository this
   type: git
-  tag: 0.1.0.1
-  location: https://github.com/chreekat/terminfo-hs/tree/0.1.0.0
+  tag: 0.2.0
+  location: https://github.com/chreekat/terminfo-hs.git
 
 library
-  ghc-options:         -Wall
-  exposed-modules:     System.Terminfo, System.Terminfo.Caps
-  other-modules:       System.Terminfo.DBParse,
-                       System.Terminfo.Types
-                       System.Terminfo.Internal
-  build-depends:       base ==4.*, errors ==1.*,
-                       bytestring ==0.*, directory ==1.*,
-                       filepath ==1.*, attoparsec ==0.*,
-                       containers ==0.5.*
+  hs-source-dirs: src
+  exposed-modules: System.Terminfo,
+                   System.Terminfo.Caps
+                   System.Terminfo.Internal
+  other-modules: System.Terminfo.DBParse,
+                 System.Terminfo.Types
+  build-depends: base <= 4.8,
+                 errors,
+                 bytestring,
+                 directory,
+                 filepath,
+                 attoparsec,
+                 containers
 
-test-suite System.Terminfo.Internal
-  type:                exitcode-stdio-1.0
-  main-is:             test.hs
-  build-depends:       base ==4.*, filepath ==1.*, directory ==1.*,
-                       errors ==1.*, QuickCheck
+test-suite test
+  type: exitcode-stdio-1.0
+  hs-source-dirs: test
+  main-is: test.hs
+  build-depends: base,
+                 filepath,
+                 directory,
+                 errors,
+                 QuickCheck,
+                 terminfo-hs
diff --git a/test.hs b/test.hs
deleted file mode 100644
--- a/test.hs
+++ /dev/null
@@ -1,42 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
-
-import Test.QuickCheck
-import Test.QuickCheck.All
-import System.Terminfo.Internal
-
-import Data.Maybe
-
-prop_useOverride ovr =
-    forAll notLikely $ \usr ->
-    forAll notLikely $ \tds ->
-    forAll oftenNull $ \defs ->
-    classify (isNothing usr && isNothing tds && null defs)
-        "Nothing else specified"$
-    classify (isJust usr && isJust tds && not (null defs))
-        "Everything else specified"$
-    locationsPure (Just ovr) usr tds defs == [ovr]
-
-notLikely = frequency [(2, return Nothing), (1, fmap Just arbitrary)]
-oftenNull = frequency [(2, return []), (1, arbitrary)]
-
-prop_includeHome usr =
-    forAll notLikely $ \tds ->
-    forAll oftenNull $ \defs ->
-    let
-        withUsr    = locationsPure Nothing (Just usr) tds defs
-        withoutUsr = locationsPure Nothing Nothing    tds defs
-    in
-    classify (isJust tds || not (null defs))
-        "Something besides HOME specified"$
-    withUsr == usr : withoutUsr
-
-prop_terminfoDirsOverridesDefaults tds =
-    forAll (oneof [return [], listOf1 arbitrary]) $ \defs ->
-    classify (not $ null defs) "Defaults specified"$
-    locationsPure Nothing Nothing (Just tds) defs
-        == parseTDVar defs tds
-
-prop_useDefaults defs =
-    locationsPure Nothing Nothing Nothing defs == defs
-
-main = $quickCheckAll
diff --git a/test/test.hs b/test/test.hs
new file mode 100644
--- /dev/null
+++ b/test/test.hs
@@ -0,0 +1,44 @@
+{-# LANGUAGE TemplateHaskell #-}
+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
+
+import Test.QuickCheck
+import System.Terminfo.Internal
+
+import Data.Maybe
+
+prop_useOverride ovr =
+    forAll notLikely $ \usr ->
+    forAll notLikely $ \tds ->
+    forAll oftenNull $ \defs ->
+    classify (isNothing usr && isNothing tds && null defs)
+        "Nothing else specified"$
+    classify (isJust usr && isJust tds && not (null defs))
+        "Everything else specified"$
+    locationsPure (Just ovr) usr tds defs == [ovr]
+
+notLikely = frequency [(2, return Nothing), (1, fmap Just arbitrary)]
+oftenNull = frequency [(2, return []), (1, arbitrary)]
+
+prop_includeHome usr =
+    forAll notLikely $ \tds ->
+    forAll oftenNull $ \defs ->
+    let
+        withUsr    = locationsPure Nothing (Just usr) tds defs
+        withoutUsr = locationsPure Nothing Nothing    tds defs
+    in
+    classify (isJust tds || not (null defs))
+        "Something besides HOME specified"$
+    withUsr == usr : withoutUsr
+
+prop_terminfoDirsOverridesDefaults tds =
+    forAll (oneof [return [], listOf1 arbitrary]) $ \defs ->
+    classify (not $ null defs) "Defaults specified"$
+    locationsPure Nothing Nothing (Just tds) defs
+        == parseTDVar defs tds
+
+prop_useDefaults defs =
+    locationsPure Nothing Nothing Nothing defs == defs
+
+return []
+
+main = $quickCheckAll
