diff --git a/CHANGES.txt b/CHANGES.txt
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,9 @@
 Changelog for Hoogle
 
+5.0.14
+    #228, add --datadir for overriding data directory on servers
+    #223, don't break on foldl'
+    #222, make sure all packages appear in the search
 5.0.13
     #219, treat the query "a->b" the same as "a -> b"
     #215, if a specified module/package is missing, give no results
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -133,6 +133,7 @@
 * [Google](http://www.google.com/), the leader in online search
 * [Hayoo](http://holumbus.fh-wedel.de/hayoo/hayoo.html), similar to Hoogle, but with less focus on type search
 * [Krugle](http://www.krugle.com/), search code, but no Haskell :(
+* [Cloogle](https://cloogle.org), for the [Clean](http://clean.cs.ru.nl) language
 
 
 ## Acknowledgements
diff --git a/hoogle.cabal b/hoogle.cabal
--- a/hoogle.cabal
+++ b/hoogle.cabal
@@ -1,7 +1,7 @@
 cabal-version:      >= 1.18
 build-type:         Simple
 name:               hoogle
-version:            5.0.13
+version:            5.0.14
 license:            BSD3
 license-file:       LICENSE
 category:           Development
@@ -76,6 +76,7 @@
         process,
         process-extras,
         resourcet,
+        storable-tuple,
         tar,
         template-haskell,
         text,
diff --git a/src/Action/CmdLine.hs b/src/Action/CmdLine.hs
--- a/src/Action/CmdLine.hs
+++ b/src/Action/CmdLine.hs
@@ -55,6 +55,7 @@
         ,https :: Bool
         ,cert :: FilePath
         ,key :: FilePath
+        ,datadir :: Maybe FilePath
         }
     | Replay
         {logs :: FilePath
@@ -135,6 +136,7 @@
     ,https = def &= help "Start an https server (use --cert and --key to specify paths to the .pem files)"
     ,cert = "cert.pem" &= typFile &= help "Path to the certificate pem file (when running an https server)"
     ,key = "key.pem" &= typFile &= help "Path to the key pem file (when running an https server)"
+    ,datadir = def &= help "Override data directory paths"
     } &= help "Start a Hoogle server"
 
 replay = Replay
diff --git a/src/Action/Generate.hs b/src/Action/Generate.hs
--- a/src/Action/Generate.hs
+++ b/src/Action/Generate.hs
@@ -224,23 +224,34 @@
                         parseHoogle (\msg -> warning $ pkg ++ ":" ++ msg) url body
 
             writeItems store $ \items -> do
-                let packages = [ fakePackage name $ "Not in Stackage, so not searched.\n" ++ T.unpack packageSynopsis
-                               | (name,Package{..}) <- Map.toList cbl, name `Set.notMember` want]
-
-                (seen, xs) <- runConduit $
+                xs <- runConduit $
                     source =$=
                     filterC (flip Set.member want . fst3) =$=
-                        ((fmap Set.fromList $ mapC fst3 =$= sinkList) |$|
-                        (((zipFromC 1 =$= consume) >> when (null include) (sourceList packages))
-                            =$= pipelineC 10 (items =$= sinkList)))
-                putStrLn ""
+                    void ((|$|)
+                        (zipFromC 1 =$= consume)
+                        (do seen <- fmap Set.fromList $ mapC fst3 =$= sinkList
 
-                let missing = [x | x <- Set.toList $ want `Set.difference` seen
-                                 , fmap packageLibrary (Map.lookup x cbl) /= Just False]
-                whenNormal $ when (missing /= []) $ do
-                    putStrLn $ "Packages missing documentation: " ++ unwords (sortOn lower missing)
-                when (Set.null seen) $
-                    exitFail "No packages were found, aborting (use no arguments to index all of Stackage)"
+                            let missing = [x | x <- Set.toList $ want `Set.difference` seen
+                                             , fmap packageLibrary (Map.lookup x cbl) /= Just False]
+                            liftIO $ putStrLn ""
+                            liftIO $ whenNormal $ when (missing /= []) $ do
+                                putStrLn $ "Packages missing documentation: " ++ unwords (sortOn lower missing)
+                            liftIO $ when (Set.null seen) $
+                                exitFail "No packages were found, aborting (use no arguments to index all of Stackage)"
+
+                            -- synthesise things for Cabal packages that are not documented
+                            forM_ (Map.toList cbl) $ \(name, Package{..}) -> when (name `Set.notMember` seen) $ do
+                                let ret prefix = yield $ fakePackage name $ prefix ++ trim (T.unpack packageSynopsis)
+                                if name `Set.member` want then
+                                    (if packageLibrary
+                                        then ret "Documentation not found, so not searched.\n"
+                                        else ret "Executable only. ")
+                                else if null include then
+                                    ret "Not on Stackage, so not searched.\n"
+                                else
+                                    return ()
+                            ))
+                    =$= pipelineC 10 (items =$= sinkList)
 
                 itemWarn <- readIORef itemWarn
                 when (itemWarn > 0) $
diff --git a/src/Action/Search.hs b/src/Action/Search.hs
--- a/src/Action/Search.hs
+++ b/src/Action/Search.hs
@@ -1,9 +1,11 @@
 {-# LANGUAGE TupleSections, RecordWildCards, ScopedTypeVariables #-}
 
-module Action.Search(actionSearch, withSearch, search,
-                    targetInfo,
-                    targetResultDisplay,
-                    action_search_test) where
+module Action.Search
+    (actionSearch, withSearch, search
+    ,targetInfo
+    ,targetResultDisplay
+    ,action_search_test
+    ) where
 
 import Control.Monad.Extra
 import Control.DeepSeq
@@ -150,6 +152,9 @@
         "ShakeOptions -> Int" === hackage "shake/docs/Development-Shake.html#v:shakeThreads"
         "is:module" === hackage "base/docs/Prelude.html"
         "visibleDataCons" === hackage "ghc/docs/TyCon.html#v:visibleDataCons"
+        "sparkle" === hackage "sparkle" -- library without Hoogle docs
+        "weeder" === hackage "weeder" -- executable in Stackage
+        "supero" === hackage "supero"
 
         let tags = completionTags store
         let asserts b x = if b then putChar '.' else error $ "Assertion failed, got False for " ++ x
diff --git a/src/Action/Server.hs b/src/Action/Server.hs
--- a/src/Action/Server.hs
+++ b/src/Action/Server.hs
@@ -54,7 +54,9 @@
         \x -> "hoogle=" `isInfixOf` x && not ("is:ping" `isInfixOf` x)
     putStrLn . showDuration =<< time
     evaluate spawned
-    dataDir <- getDataDir
+    dataDir <- case datadir of
+        Just d -> return d
+        Nothing -> getDataDir
     haddock <- maybe (return Nothing) (fmap Just . canonicalizePath) haddock
     withSearch database $ \store ->
         server log cmd $ replyServer log local haddock store cdn home (dataDir </> "html") scope
@@ -172,8 +174,8 @@
                 (a,[]) -> a ++ [("hoogle",x)]
                 (a,(_,x1):b) -> a ++ [("hoogle",x1 ++ " " ++ x)] ++ b
 
-        f cat val = "<a class='minus' href='" ++ add ("-" ++ cat ++ ":" ++ val) ++ "'></a>" ++
-                    "<a class='plus' href='" ++ add (cat ++ ":" ++ val) ++ "'>" ++
+        f cat val = "<a class=\"minus\" href=\"" ++ add ("-" ++ cat ++ ":" ++ val) ++ "\"></a>" ++
+                    "<a class=\"plus\" href=\"" ++ add (cat ++ ":" ++ val) ++ "\">" ++
                     (if cat == "package" then "" else cat ++ ":") ++ val ++ "</a>"
 
 
diff --git a/src/General/Conduit.hs b/src/General/Conduit.hs
--- a/src/General/Conduit.hs
+++ b/src/General/Conduit.hs
@@ -69,16 +69,8 @@
 
 linesCR :: Monad m => Conduit Str m Str
 linesCR = linesC =$= mapC f
-    where f x | Just (x, '\r') <- bsUnsnoc x = x
+    where f x | Just (x, '\r') <- BS.unsnoc x = x
               | otherwise = x
-
-bsUnsnoc :: BS.ByteString -> Maybe (BS.ByteString, Char)
-#if __GLASGOW_HASKELL__ < 708
-bsUnsnoc x | BS.null x = Nothing
-           | otherwise = Just (BS.init x, BS.last x)
-#else
-bsUnsnoc = BS.unsnoc
-#endif
 
 sourceLStr :: Monad m => LStr -> Producer m Str
 sourceLStr = sourceList . lstrToChunks
diff --git a/src/General/Util.hs b/src/General/Util.hs
--- a/src/General/Util.hs
+++ b/src/General/Util.hs
@@ -43,13 +43,9 @@
 import Control.DeepSeq
 import Control.Exception.Extra
 import Test.QuickCheck
-import Foreign.Storable
 import Data.Int
 import System.IO
 import System.Exit
-#if __GLASGOW_HASKELL__< 710
-import System.Locale
-#endif
 import Prelude
 
 
@@ -238,14 +234,6 @@
     case res of
         Left e -> do msg <- showException e; evaluate $ rnf msg; error msg
         Right v -> do evaluate $ rnf v; return v
-
--- I would like to use the storable-tuple package, but it's not in Stackage
-instance forall a b . (Storable a, Storable b) => Storable (a,b) where
-    sizeOf x = sizeOf (fst x) + sizeOf (snd x)
-    alignment x = alignment (fst x) `max` alignment (snd x) -- dodgy, but enough for my purposes
-    peekByteOff ptr pos = liftM2 (,) (peekByteOff ptr pos) (peekByteOff ptr $ pos + sizeOf (undefined :: a))
-    pokeByteOff ptr pos (a,b) = pokeByteOff ptr pos a >> pokeByteOff ptr (pos + sizeOf (undefined :: a)) b
-
 
 data Average a = Average !a !Int deriving Show -- a / b
 
diff --git a/src/Output/Tags.hs b/src/Output/Tags.hs
--- a/src/Output/Tags.hs
+++ b/src/Output/Tags.hs
@@ -6,6 +6,7 @@
 import Data.List.Extra
 import Data.Tuple.Extra
 import Data.Maybe
+import Foreign.Storable.Tuple()
 import qualified Data.Map as Map
 import qualified Data.Set as Set
 import qualified Data.Vector.Storable as V
