parseDisplay xs = parse exp "" xs where
    exp = do
        p <- option "" (try $ skip '/') <?> "protocol"
        h <- option "" ((try ipv6) <|> (try host)) <?> "host"
        d <- char ':' >> integer <?> "display"
        s <- option 0 (char '.' >> integer <?> "screen")
        return $ DispName p h d s
    eat c s = char c >> return s
    anyExcept c = many1 (noneOf [c])
    skip c = anyExcept c >>= eat c
    ipv6 = char '[' >> skip ']'
    host = anyExcept ':'
    integer :: Parser Int
    integer = many1 digit >>= \x -> return $ read x

-- | Given a launchd display-string, return the appropriate
-- DispName structure for it.
parseDisplay xs = parse exp "" xs where
    exp = do
        p <- option "" (try $ skip '/') <?> "protocol"
        h <- option "" ((try ipv6) <|> (try host)) <?> "host"
        d <- char ':' >> integer <?> "display"
        s <- option 0 (char '.' >> integer <?> "screen")
        return $ DispName p h d s
    eat c s = char c >> return s
    anyExcept c = many1 (noneOf [c])
    skip c = anyExcept c >>= eat c
    ipv6 = char '[' >> skip ']'
    host = anyExcept ':'
    integer :: Parser Int
    integer = many1 digit >>= \x -> return $ read x

-- | Given a launchd display-string, return the appropriate
-- DispName structure for it.
parseDisplay xs = parse exp "" xs where
    exp = do
        p <- option "" (try $ skip '/') <?> "protocol"
        h <- option "" ((try ipv6) <|> (try host)) <?> "host"
        d <- char ':' >> integer <?> "display"
        s <- option 0 (char '.' >> integer <?> "screen")
        return $ DispName p h d s
    eat c s = char c >> return s
    anyExcept c = many1 (noneOf [c])
    skip c = anyExcept c >>= eat c
    ipv6 = char '[' >> skip ']'
    host = anyExcept ':'
    integer :: Parser Int
    integer = many1 digit >>= \x -> return $ read x

-- | Given a launchd display-string, return the appropriate
-- DispName structure for it.