diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/doc/LICENSE b/doc/LICENSE
new file mode 100644
--- /dev/null
+++ b/doc/LICENSE
diff --git a/scan.cabal b/scan.cabal
new file mode 100644
--- /dev/null
+++ b/scan.cabal
@@ -0,0 +1,47 @@
+cabal-version:      >= 1.6
+build-type:         Simple
+name:               scan
+version:            0.1.0.0
+license:            BSD3
+license-file:       doc/LICENSE
+category:           Development
+author:             chr.maeder@web.de
+maintainer:         chr.maeder@web.de
+copyright:          Christian Maeder 2010
+synopsis:           lexical style suggestions for source code
+description:
+  scan checks the format of your source code. It reports
+  (and partly repairs if given the @-@ option):
+
+  non-ascii characters,
+  tabs or carriage returns,
+  trailing white spaces,
+  backslash at line end,
+  unconventional comment delimiters,
+  too long lines,
+  too many consecutive blank lines,
+  not a single blank between tokens,
+  not a single final newline,
+  no spaces after commas,
+  spaces between parens and infix operators in sections,
+  bad layout (wrt @do@ or @of@).
+
+  It may be useful in conjunction with
+  <http://community.haskell.org/~ndm/hlint/>
+  to give suggestions on how to improve your source code.
+
+  Repairing is not suited for slices (aka @$(...)@) in template haskell or if
+  you like to align your code at @=@ or @->@ in the middle of a line (thus
+  wanting multiple blanks). Furthermore layout may be destroyed by inserting
+  or deleting blanks, but this is an indication for improving layout anyway.
+  Also lines may become too long after inserting blanks.
+
+homepage:           http://projects.haskell.org/style-scanner
+stability:          experimental
+
+executable scan
+    build-depends:      base < 5, parsec < 3 || >= 3
+    hs-source-dirs:     src
+    main-is:            scan.hs
+
+    ghc-options: -Wall
diff --git a/src/scan.hs b/src/scan.hs
new file mode 100644
--- /dev/null
+++ b/src/scan.hs
@@ -0,0 +1,84 @@
+{- |
+Module      :  scan.hs
+Description :  the standalone Haskell style scanner
+Copyright   :  (c) Christian Maeder 2010
+License     :  BSD
+
+Maintainer  :  chr.maeder@web.de
+Stability   :  experimental
+Portability :  portable
+
+the Haskell style scanner
+-}
+
+module Main where
+
+import Control.Monad
+
+import Data.Char
+import Data.List
+
+import System.Environment
+import Text.ParserCombinators.Parsec
+
+import Language.Haskell.Scanner
+
+main :: IO ()
+main = do
+  args <- getArgs
+  let (opts, files) = span (== "-") args
+      b = null opts
+  case files of
+    [] -> putStrLn "missing file argument"
+    _ -> mapM_ (process $ null opts) $ if b then files else
+         take 3 files -- do not spoil more than 3 files
+
+process :: Bool -> String -> IO ()
+process b f = do
+  str <- readFile f
+  let nls = zip [1 ..] $ lines str
+      bls = checkBlankLines f 1 nls
+  when b $ mapM_ (checkLine f) nls
+  when (b && not (isSuffixOf "\n" str))
+    $ diag f (length nls) "missing final newline"
+  when b $ mapM_ putStrLn bls
+  case parse scan f str of
+    Right ts -> let x = splitLines ts in
+      if b then let o = showScan x in unless (null o) $ putStrLn o else
+      let rstr = processScan x in
+      if rstr == str then putStrLn $ "no changes in \"" ++ f ++ "\"" else do
+      writeFile (f ++ ".bak") str
+      writeFile f rstr
+      putStrLn $ "updated \"" ++ f ++ "\" (and created .bak)"
+    Left err -> fail $ show err
+
+checkBlankLines :: FilePath -> Int -> [(Int, String)] -> [String]
+checkBlankLines f c l = case l of
+  [] -> if c > 0 then ["trailing blank lines"] else []
+  (n, s) : r ->
+    if null $ filter (not . isSpace) s then
+      if c >= 2 then
+        diagStr f n "too many consecutive blank lines"
+        : checkBlankLines f (- 100) r
+      else checkBlankLines f (c + 1) r
+    else checkBlankLines f 0 r
+
+diagStr :: FilePath -> Int -> String -> String
+diagStr f n str = "\"" ++ f ++ "\" (line " ++ show n ++ ") " ++ str
+
+diag :: FilePath -> Int -> String -> IO ()
+diag f n = putStrLn . diagStr f n
+
+checkLine :: FilePath -> (Int, String) -> IO ()
+checkLine f (n, s) = do
+  let r = reverse s
+      rt = dropWhile isSpace r
+      l = length rt
+      trailBSlash = takeWhile (== '\\') rt
+      badChars = filter (\ c -> not $ isAscii c && isPrint c) s
+  when (l > 80) $
+    diag f n $ "too long line (" ++ show l ++ " chars)"
+  unless (null badChars) $
+    diag f n $ "contains undesirable characters: " ++ show badChars
+  unless (null trailBSlash) $
+    diag f n "back slash at line end (may disturb cpp)"
